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

Reviewed-on: http://git.feashow.cn/clay/tunnel-cloud-web/pulls/63
This commit is contained in:
odjbin
2023-12-09 06:23:07 +00:00
13 changed files with 17218 additions and 152 deletions

View File

@@ -16,7 +16,7 @@ steps:
- export NODE_MODULES_PATH=`pwd`/node_modules
- npm config set registry https://registry.npm.taobao.org
- set NODE_OPTIONS=--openssl-legacy-provider
# - npm install
- npm install
- npm run build
- echo $NODE_MODULES_PATH
- cp -r dist /app/build/$DRONE_REPO_NAME

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 951 KiB

16669
public/tunnelModel/chanel.gltf Normal file

File diff suppressed because one or more lines are too long

View File

@@ -42,8 +42,9 @@ html, body, #app, .el-container, .el-aside, .el-main {
width: 60px;
height: 60px;
}
.select-active{
color: #11EAF2!important;
.select-active {
color: #11EAF2 !important;
}
}
}
@@ -163,7 +164,34 @@ html, body, #app, .el-container, .el-aside, .el-main {
margin-left: -925px;
background-image: url('../images/topAndDown/sp_dbbj.png');
.el-carousel__mask {
display: none;
}
.el-carousel {
width: 1250px;
height: 146px;
padding-top: 35px;
.el-carousel__container {
width: 1250px;
.el-carousel__arrow--left {
display: none;
}
.el-carousel__arrow--right {
display: none;
}
}
.el-carousel__indicators {
display: none;
}
}
.arrow {
cursor: pointer;
margin: 50px 0 0 263px;
width: 46px;
height: 54px;
@@ -172,32 +200,31 @@ html, body, #app, .el-container, .el-aside, .el-main {
.btn {
width: 100%;
display: flex;
align-items: center;
justify-content: space-around;
margin-top: 14px;
font-size: 26px;
color: #9FC3CD;
.el-carousel__item {
left: 19%;
}
> div {
display: flex;
justify-content: center;
padding-top: 5px;
width: 158px;
height: 50px;
background-image: url('../images/topAndDown/sp_icon_sdqhx.png');
}
> div:nth-child(2) {
.is-active {
margin-top: -5px;
color: #FFFFFF;
padding-top: 7px;
width: 201px;
height: 62px;
background-image: url('../images/topAndDown/sp_icon_sdqhd.png');
}
> div:first-child, > div:last-child {
padding-top: 5px;
width: 158px;
height: 50px;
background-image: url('../images/topAndDown/sp_icon_sdqhx.png');
}
}
.right {

View File

@@ -1,13 +1,12 @@
<template>
<div id="air-info">
<div class="fan-speed">
<img src="../../../../public/images/airInfo/fan-v-icon.png" alt="" />
<img src="/images/airInfo/fan-v-icon.png" alt="" />
<div class="fan-info">
<div class="input-fan"><span>风速</span><span>进风13m/s</span></div>
<div class="output-fan"><span>风速</span><span>出风13m/s</span></div>
</div>
</div>
unit="%"
<item-info
:wp="info"
icon="/images/airInfo/o2-icon.png"
@@ -62,6 +61,12 @@ const info3 = reactive({
value: 80, //测量值
point: 88, //阈值
});
setInterval(() => {
info.value = parseInt(Math.random() * 10) * 10;
info1.value = parseInt(Math.random() * 10) * 10;
info2.value = parseInt(Math.random() * 10) * 10;
info3.value = parseInt(Math.random() * 10) * 10;
}, 2000);
</script>
<style lang="scss" scoped>

View File

@@ -1,10 +1,65 @@
<template>
<div id="bad-gas-info">
<div class="title">有害气体</div>
<div class="info-list">
<gas-info-item :gasInfo="gasInfo" />
<gas-info-item :gasInfo="gasInfo2" />
<gas-info-item :gasInfo="gasInfo3" />
<gas-info-item :gasInfo="gasInfo4" />
<gas-info-item :gasInfo="gasInfo5" />
<gas-info-item :gasInfo="gasInfo6" />
</div>
</div>
</template>
<script setup></script>
<script setup>
import { reactive } from "vue";
import gasInfoItem from "./childComps/gasInfoItem.vue";
const gasInfo = reactive({
name: "一氧化硫", //气体名称
max: 100, //最大值
value: 10, //传感器值
point: 50, //阈值
});
const gasInfo2 = reactive({
name: "一氧化氮", //气体名称
max: 100, //最大值
value: 10, //传感器值
point: 10, //阈值
});
const gasInfo3 = reactive({
name: "一氧化碳", //气体名称
max: 100, //最大值
value: 10, //传感器值
point: 70, //阈值
});
const gasInfo4 = reactive({
name: "二氧化碳", //气体名称
max: 100, //最大值
value: 10, //传感器值
point: 40, //阈值
});
const gasInfo5 = reactive({
name: "硫化氢", //气体名称
max: 100, //最大值
value: 10, //传感器值
point: 20, //阈值
});
const gasInfo6 = reactive({
name: "二氧化硫", //气体名称
max: 100, //最大值
value: 10, //传感器值
point: 20, //阈值
});
setInterval(() => {
gasInfo.value = parseInt(Math.random() * 10) * 10;
gasInfo2.value = parseInt(Math.random() * 10) * 10;
gasInfo3.value = parseInt(Math.random() * 10) * 10;
gasInfo4.value = parseInt(Math.random() * 10) * 10;
gasInfo6.value = parseInt(Math.random() * 10) * 10;
gasInfo5.value = parseInt(Math.random() * 10) * 10;
}, 2000);
</script>
<style lang="scss" scoped>
#bad-gas-info {
@@ -25,5 +80,13 @@
line-height: 45px;
margin: 22px 0px 0px 62px;
}
.info-list {
width: 100%;
height: calc(621px - 45px - 22px);
display: flex;
flex-wrap: wrap;
justify-content: space-around;
padding: 10px 0px 0px 10px;
}
}
</style>

View File

@@ -0,0 +1,125 @@
<template>
<div id="gas-info-item">
<div class="info" ref="container"></div>
<div class="name">{{ gasInfo.name }}</div>
</div>
</template>
<script setup>
import { defineProps, ref, reactive, watch, onMounted } from "vue";
import * as Echarts from "echarts";
let e_info;
let params = defineProps({
gasInfo: Object,
});
// const gasInfo = {
// name: "氧气", //气体名称
// max: 100, //最大值
// value: 66, //传感器值
// point: 90, //阈值
// };
const option = {
series: [
{
type: "gauge",
startAngle: -90,
endAngle: -450,
radius: "100%",
center: ["50%", "50%"],
pointer: {
show: false,
},
progress: {
show: true,
overlap: false,
roundCap: true,
clip: false,
itemStyle: {
color: `${
params.gasInfo.value > params.gasInfo.point ? "#F94236" : "#7EDFEC"
}`,
},
},
max: params.gasInfo.max,
splitLine: {
show: false,
},
axisTick: {
show: false,
},
axisLabel: {
show: false,
},
data: [
{
value: params.gasInfo.value,
fontSize: 2100,
detail: {
valueAnimation: true,
offsetCenter: ["0%", "0%"],
fontSize: 26,
},
},
],
axisLine: {
lineStyle: {
width: 25,
color: [[1, "#0a4265"]],
},
},
detail: {
width: 100,
height: 14,
fontSize: 26,
color: `${
params.gasInfo.value > params.gasInfo.point ? "#F94236" : "#FFCE23"
}`,
formatter: "Vo{value}%",
},
},
],
};
let container = ref(null);
onMounted(handleOnMounted);
function handleOnMounted() {
e_info = Echarts.init(container.value);
e_info.setOption(option);
}
watch(
() => params.gasInfo.value,
(value) => {
option.series[0].data[0].value = value;
// 判断是否超过阈值则进度条变红
value > params.gasInfo.point
? (option.series[0].progress.itemStyle.color = "#F94236")
: (option.series[0].progress.itemStyle.color = "#7EDFEC");
// 字体颜色
value > params.gasInfo.point
? (option.series[0].detail.color = "#F94236")
: (option.series[0].detail.color = "#FFCE23");
e_info.setOption(option);
}
);
</script>
<style lang="scss" scoped>
#gas-info-item {
width: 231px;
text-align: center;
.info {
width: 200px;
height: 200px;
}
.name {
width: 112px;
height: 37px;
font-size: 28px;
font-family: MicrosoftYaHei;
color: #ffffff;
line-height: 37px;
margin: 10px auto 0px;
}
}
</style>

View File

@@ -11,21 +11,21 @@
<div class="option-nav">
<div class="state">
<div :class="{ stopColor: !isStart }">
<span> <img :src="stateIcon1" alt="" />状态</span
<span> <img :src="stateIcon1" alt=""/>状态</span
><span>{{ state }}</span>
</div>
<div class="switch">
<div
id="auto"
:class="{ active: isStart }"
@click="isStart = true"
id="auto"
:class="{ active: isStart }"
@click="isStart = true"
>
启动
</div>
<div
id="stop"
:class="{ active: !isStart }"
@click="isStart = false"
id="stop"
:class="{ active: !isStart }"
@click="isStart = false"
>
停止
</div>
@@ -41,7 +41,7 @@
<div class="edit-power">
<span style="color: white">当前功率</span>
<span class="units"
><input
><input
type="number"
min="0"
v-model="fan01_option.series[0].data[0].value"
@@ -61,21 +61,21 @@
<div class="option-nav">
<div class="state">
<div :class="{ stopColor: !isStart2 }">
<span><img :src="stateIcon2" alt="" />状态{{ state2 }}</span
<span><img :src="stateIcon2" alt=""/>状态{{ state2 }}</span
><span></span>
</div>
<div class="switch">
<div
id="auto"
:class="{ active: isStart2 }"
@click="isStart2 = true"
id="auto"
:class="{ active: isStart2 }"
@click="isStart2 = true"
>
启动
</div>
<div
id="stop"
:class="{ active: !isStart2 }"
@click="isStart2 = false"
id="stop"
:class="{ active: !isStart2 }"
@click="isStart2 = false"
>
停止
</div>
@@ -91,7 +91,7 @@
<div class="edit-power">
<span style="color: white">当前功率</span>
<span class="units"
><input
><input
type="number"
min="0"
v-model="fan02_option.series[0].data[0].value"
@@ -107,7 +107,7 @@
<script setup>
import * as echarts from "echarts";
import { ref, reactive, onMounted, computed, watch } from "vue";
import {ref, reactive, onMounted, computed, watch} from "vue";
onMounted(handleOnMounted);
@@ -121,60 +121,109 @@ const option = {
series: [
{
type: "gauge",
progress: {
show: true,
width: 15,
lineStyle: {
color: "yellow",
},
},
axisLine: {
lineStyle: {
width: 5,
},
},
axisTick: {
show: false,
},
splitLine: {
length: 15,
lineStyle: {
width: 1,
color: "#099",
},
},
axisLabel: {
show: false,
distance: 25,
color: "#999",
fontSize: 20,
},
startAngle: -120,
endAngle: -420,
pointer: {
show: false,
},
anchor: {
show: false,
showAbove: true,
size: 0,
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
}
},
},
title: {
show: true,
max: 1000,
splitLine: {
show: false,
},
detail: {
valueAnimation: true,
fontSize: 40,
offsetCenter: [0, "0%"],
formatter: "{value}Hz",
color: "white",
axisTick: {
show: true,
splitNumber: 1,
length: 10,
},
axisLabel: {
show: false,
},
data: [
{
value: 10,
value: 50,
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}",
},
},
],
};
@@ -182,66 +231,116 @@ const option2 = {
series: [
{
type: "gauge",
progress: {
show: true,
width: 15,
lineStyle: {
color: "yellow",
},
},
axisLine: {
lineStyle: {
width: 5,
},
},
axisTick: {
show: false,
},
splitLine: {
length: 15,
lineStyle: {
width: 1,
color: "#099",
},
},
axisLabel: {
show: false,
distance: 25,
color: "#999",
fontSize: 20,
},
startAngle: -120,
endAngle: -420,
pointer: {
show: false,
},
anchor: {
show: false,
showAbove: true,
size: 0,
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
}
},
},
title: {
show: true,
max: 1000,
splitLine: {
show: false,
},
detail: {
valueAnimation: true,
fontSize: 40,
offsetCenter: [0, "0%"],
formatter: "{value}Hz",
color: "white",
axisTick: {
show: true,
splitNumber: 1,
length: 10,
},
axisLabel: {
show: false,
},
data: [
{
value: 10,
value: 500,
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}",
},
},
],
};
const fan01_option = reactive(option, { deep: true });
const fan02_option = reactive(option2, { deep: true });
const fan01_option = reactive(option, {deep: true});
const fan02_option = reactive(option2, {deep: true});
function handleOnMounted() {
Echarts_info1 = echarts.init(info1.value);
Echarts_info1.setOption(fan01_option);
@@ -263,18 +362,18 @@ let state = computed(() => {
return isStart.value ? "启动" : "停止";
});
const stateIcon1 = computed(() =>
isStart.value
? "/images/fanInfo/blue-state-icon.png"
: "/images/fanInfo/red-state-icon.png"
isStart.value
? "/images/fanInfo/blue-state-icon.png"
: "/images/fanInfo/red-state-icon.png"
);
const isStart2 = ref(true);
let state2 = computed(() => {
return isStart2.value ? "启动" : "停止";
});
const stateIcon2 = computed(() =>
isStart2.value
? "/images/fanInfo/blue-state-icon.png"
: "/images/fanInfo/red-state-icon.png"
isStart2.value
? "/images/fanInfo/blue-state-icon.png"
: "/images/fanInfo/red-state-icon.png"
);
let is = ref("isInput");
// 功率是否自动
@@ -288,14 +387,18 @@ let isSAuto2 = ref("false");
height: 24px;
border: 2px solid #38cafb;
border-radius: 50%;
text-align: center;
display: flex;
align-items: center;
justify-content: center;
}
::v-deep .el-radio__label {
font-size: 28px;
font-family: MicrosoftYaHei;
color: #38cafb;
line-height: 37px;
}
#fan_info {
height: 521px;
width: 830px;
@@ -311,6 +414,7 @@ let isSAuto2 = ref("false");
background-repeat: no-repeat;
//clip-path: polygon(0% 0%, 40% 0%, 48% 15%, 100% 15%, 100% 100%, 0% 100%);
color: #2fb0df;
.title {
width: 40%;
text-align: left;
@@ -322,17 +426,34 @@ let isSAuto2 = ref("false");
color: #38cafb;
line-height: 42px;
}
.fans {
height: calc(100% - 30px);
.fan-item {
height: 50%;
display: flex;
font-size: 14px;
.echart {
height: 100%;
width: 30%;
margin: 0px 0px 0px 10px;
position: relative;
}
.echart::after {
content: "Hz";
font-size: 24px;
font-family: MicrosoftYaHei, MicrosoftYaHei;
font-weight: bold;
color: #ffffff;
line-height: 31px;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, 60%);
}
.fan-name {
width: 39px;
height: 140px;
@@ -344,9 +465,11 @@ let isSAuto2 = ref("false");
margin-right: 42px;
transform: translateY(33%);
}
.option-nav {
display: flex;
width: 70%;
.state {
flex: 1;
display: flex;
@@ -357,10 +480,12 @@ let isSAuto2 = ref("false");
color: #38cafb;
line-height: 35px;
gap: 33px;
img {
margin-right: 4px;
transform: translateY(15%);
}
.switch {
display: flex;
width: 160px;
@@ -372,6 +497,7 @@ let isSAuto2 = ref("false");
font-weight: bold;
color: #127399;
line-height: 35px;
& > div {
flex: 1;
text-align: center;
@@ -391,6 +517,7 @@ let isSAuto2 = ref("false");
color: #38cafb;
line-height: 37px;
gap: 33px;
.edit-power {
margin-top: 10px;
@@ -413,9 +540,11 @@ let isSAuto2 = ref("false");
}
}
}
.units {
position: relative;
}
.units::after {
content: "Hz";
@@ -428,10 +557,12 @@ let isSAuto2 = ref("false");
color: #38cafb;
line-height: 37px;
}
.active {
color: white;
background: #0f7da9;
}
.stopColor {
color: red;
}

View File

@@ -1,12 +1,7 @@
<template>
<div id="scene" ref="content">
<dev-info ref="info" :devInfo="devInfo" />
<edit-dev
ref="edit"
@addDev="handleAddDev"
@removeDev="handleRemoveDev"
:hasDev="hasDevice"
/>
<edit-dev ref="edit" @addDev="handleAddDev" @removeDev="handleRemoveDev" :hasDev="hasDevice" />
</div>
</template>
@@ -25,7 +20,7 @@ import {
CSS3DSprite,
} from "three/addons/renderers/CSS3DRenderer.js";
import { OBJLoader } from "three/examples/jsm/loaders/OBJLoader";
import { RGBELoader } from "three/examples/jsm/loaders/RGBELoader"
import DevInfo from "./childComp/DevInfo.vue";
import EditDev from "./childComp/EditDev.vue";
import { onMounted, reactive, ref } from "vue";
@@ -38,20 +33,23 @@ const edit = ref(null);
const num = 10000;
let demo; //定义demo全局变量
const loader = new OBJLoader();
let hdrLoader = new RGBELoader();
let backColorSet = three.sRGBEncoding;
// 模版挂载后
onMounted(handleMounted);
// 处理回调
async function handleMounted() {
const doms = [info.value.$el, edit.value.$el];
demo = new ThreeDScene(three, content.value);
demo.loadModel(GLTFLoader, "./assets/tunnelModel/chanel.glb");
demo.loadModel(GLTFLoader, "./assets/tunnelModel/chanel.gltf");
demo.addOrbitControls(OrbitControls);
demo.addTween(TWEEN);
demo.addCSS3Renderer(CSS3DRenderer, CSS3DSprite, doms);
demo.setDistance(10);
lClickCallback(demo); //左键回调
rClickCallback(demo); //右键回调
//加载HDR背景图片
demo.loadBackground(hdrLoader, backColorSet)
// 初始化设备模型
try {
const deviceList = [];
@@ -80,7 +78,7 @@ function loadModel(path) {
(obj) => {
resolve(obj);
},
(xhr) => {},
(xhr) => { },
(err) => {
reject(err);
}

View File

@@ -41,13 +41,13 @@ export default class Demo {
this.camera = new this.THREE.PerspectiveCamera(
75,
window.innerWidth / window.innerHeight,
0.1,
1,
1000
);
this.camera.position.z = 130;
this.camera.position.y = 35;
this.camera.position.x = 40;
this.camera.position.z = -60;
this.camera.position.y = 20;
this.camera.position.x = -30;
this.camera.lookAt(0, 0, 1000);
// 初始化渲染器
@@ -73,6 +73,7 @@ export default class Demo {
// 轨道控制器更新
if (this.orbitControls) {
this.orbitControls.update();
// console.log(this.camera.position);
}
// 摄像头移动动画
@@ -127,13 +128,12 @@ export default class Demo {
return new Promise((resolve, reject) => {
this.gltfloader = new GLTFLoader();
this.gltfloader.load(
"/tunnelModel/chanel.glb",
"/tunnelModel/chanel.gltf",
(gltf) => {
gltf.scene.traverse((child) => {
this._forModels(child);
});
this.scene.add(gltf.scene);
// 加载完后可执行函数
this._afterLoaded(gltf.scene);
resolve(gltf);
@@ -372,4 +372,14 @@ export default class Demo {
setDistance(distance = 10) {
this.distance = distance;
}
loadBackground(hdrLoader, backColorSet) {
// hdrLoader.load("/images/background/background.hdr", (texture) => {
// texture.mapping = this.THREE.EquirectangularReflectionMapping;
// this.scene.background = texture;
// this.scene.environment = texture;
// })
this.scene.background = new this.THREE.TextureLoader().load("/images/background/background.png", function (texture) {
texture.encoding = backColorSet;
});
}
}

View File

@@ -9,7 +9,8 @@
<script setup>
import WindPressureItem from "./childComps/WindPressureItem.vue";
const wpList = [
import { reactive } from "vue";
const wpList = reactive([
{
windPId: 1, //编号
max: 120, //最大值
@@ -70,7 +71,12 @@ const wpList = [
value: 99, //测量值
point: 70, //阈值
},
];
]);
setInterval(() => {
wpList.forEach((item) => {
item.value = parseInt(Math.random() * 10) * 10;
});
}, 2000);
</script>
<style lang="scss" scoped>

View File

@@ -51,13 +51,15 @@
<div v-else class="shrink-right" @click="closeRight"></div>
</div>
<div class="switch-btn">
<div class="arrow"></div>
<div class="btn">
<div>一号隧道</div>
<div>二号隧道</div>
<div>三号隧道</div>
</div>
<div class="arrow right"></div>
<div class="arrow" @click="previousBtn"></div>
<el-carousel height="150px" type="card" ref="tunnelBtn" :autoplay="false">
<div class="btn">
<el-carousel-item v-for="(item,index) in tunnelList" :key="item.value">
{{ item.name }}
</el-carousel-item>
</div>
</el-carousel>
<div class="arrow right" @click="nextBtn"></div>
</div>
</div>
</template>
@@ -76,13 +78,37 @@ import {useAuthStore} from '@/store/userstore.js'
const authStore = useAuthStore()
const router = useRouter()
const selectIndex=ref(1)
const selectIndex = ref(1)
const drawerLeft = ref(true)
const drawerRight = ref(true)
const currentSite = ref('松江站')
const currentUser = ref('admin')
const currentDate = ref(dateFormat())
const tunnelBtn = ref()
const tunnelList = ref([
{
value: 0,
name: '一号隧道'
}, {
value: 1,
name: '二号隧道'
}, {
value: 2,
name: '三号隧道'
}, {
value: 3,
name: '四号隧道'
}, {
value: 4,
name: '五号隧道'
}, {
value: 5,
name: '六号隧道'
}, {
value: 6,
name: '七号隧道'
},
])
const manageSelect = () => {
// getInfo();
};
@@ -96,6 +122,12 @@ const handleLogout = () => {
authStore.userLogout()
router.push('/login')
}
const previousBtn = () => {
tunnelBtn.value.prev()
}
const nextBtn = () => {
tunnelBtn.value.next();
}
</script>
<style lang="scss" scoped>