first commit

This commit is contained in:
2025-12-24 18:19:05 +08:00
commit 78407f1cbd
283 changed files with 170690 additions and 0 deletions

View File

@@ -0,0 +1,115 @@
<template>
<DialogComponent title="气象设备" width="395" :draggable="true" :modal="false" @close="$emit('close')">
<div class="content-wrapper">
<ul class="list-wrapper">
<li class="list-item" v-for="(item, index) in items" :key="index">
<span class="label">{{ item.label }}</span>
<span class="value">{{ model[item.prop] }}</span>
</li>
</ul>
</div>
</DialogComponent>
</template>
<script setup>
import { reactive } from 'vue'
import DialogComponent from '@/components/Dialog/index.vue'
const items = [
{
label: '深度观测站编号',
prop: 'prop1'
},
{
label: '雷达水位',
prop: 'prop2'
},
{
label: '压力式水位',
prop: 'prop3'
},
{
label: '温度',
prop: 'prop4'
},
{
label: '倾角',
prop: 'prop5'
},
{
label: '当前时间',
prop: 'prop6'
}
]
const model = reactive({
prop1: 'XD111',
prop2: '30m',
prop3: '30m',
prop4: '30℃',
prop5: '30°',
prop6: '2025-09-17 10:43:05'
})
</script>
<style lang="scss" scoped>
.content-wrapper {
width: 100%;
// height: 300px;
overflow: auto;
.list-wrapper {
width: 100%;
display: flex;
flex-direction: column;
gap: 8px;
.list-item {
width: 100%;
display: flex;
height: 18px;
align-items: center;
.label {
width: 120px;
font-size: 14px;
color: #00C0FFFF;
text-align: left;
}
.value {
color: #FFFFFFFF;
font-size: 14px;
}
}
.subtitle {
width: 100%;
height: 28px;
background-color: #00C0FF33;
color: #00C0FFFF;
font-size: 14px;
display: flex;
justify-content: space-between;
align-items: center;
padding: 0 4px;
box-sizing: border-box;
&::after {
content: '';
display: block;
width: 14px;
height: 14px;
background-image: url('@/assets/images/common/icon-triangle.png');
background-size: 100% 100%;
background-repeat: no-repeat;
}
}
}
}
</style>

View File

@@ -0,0 +1,56 @@
<template>
<DialogComponent @mousedown="drag" :style="{ resize: 'both', overflow: 'auto' }" v-if="visible && option[type]" :title="option[type].title" :width="type==='_UAV' ? 1800:395" :draggable="true" :modal="false" @close="close">
<component :is="option[type].component" ref="component"/>
</DialogComponent>
</template>
<script setup>
import { computed, nextTick, onMounted, onUnmounted, ref } from 'vue'
import DialogComponent from '@/components/Dialog/screen.vue'
import MonitorComponent from './monitor.vue'
import UAVComponent from './uav.vue'
import MeteorologyComponent from './meteorology.vue'
import useMapStore from '@/store/modules/map'
import { dragEvent } from '@/utils/common'
const mapStore = useMapStore()
const visible = computed(() => mapStore.windowInfo.visible)
const type = computed(() => mapStore.windowInfo.type)
const data = computed(() => mapStore.windowInfo.data)
const option = computed(() => ({
_monitor: {
title: '监控设备',
component: MonitorComponent
},
_UAV: {
title: '无人机设备',
component: UAVComponent
},
_environmental: {
title: data.value?.videoType || '环境监测设备',
component: MeteorologyComponent
}
}))
const component = ref(null)
const close = () => {
mapStore.updateWindowInfo(false)
}
/**
* 拖拽事件
* @param e
*
*/
const drag = (e) => {
dragEvent(e, 'el-dialog-title', () => {
if(component.value.HikCCTV) {
component.value.HikCCTV.initResize(false)
}
})
}
</script>
<style lang="scss" scoped>
</style>

View File

@@ -0,0 +1,218 @@
<template>
<div class="content-wrapper">
<ul class="list-wrapper">
<li class="list-item" v-for="(item, index) in items" :key="index">
<span class="label">{{ item.label }}</span>
<span class="value">{{ model[item.prop] }}{{ item.unit }}</span>
</li>
</ul>
</div>
</template>
<script setup>
import { computed, reactive, ref, watch } from 'vue'
// import { getWaterwayVelocity, getWaterwayWeather } from '@/api/identification.js'
import { dayjs } from 'element-plus'
import useMapStore from '@/store/modules/map'
const mapStore = useMapStore()
const data = computed(() => mapStore.windowInfo.data)
const velocityItems = [
{
label: '深度观测站编号',
prop: 'deepSiteCode'
},
{
label: '雷达流速',
prop: 'radarVelocity',
unit: 'km/s'
},
{
label: '雷达水位',
prop: 'radarLevel',
unit: 'm'
},
{
label: '压力式水位',
prop: 'pressureLevel',
unit: 'm'
},
{
label: '温度',
prop: 'temperature',
unit: '℃'
},
{
label: '倾角',
prop: 'angle',
unit: '°'
},
{
label: '当前时间',
prop: 'createTime'
}
]
const velocityModel = {
deepSiteCode: 0,
radarVelocity: 0,
radarLevel: 0,
pressureLevel: 0,
temperature: 0,
angle: 0,
createTime: null
}
const weatherItems = [
{
label: '深度观测站编号',
prop: 'deepSiteCode'
},
{
label: '温度',
prop: 'temperature',
unit: '℃'
},
{
label: '湿度',
prop: 'humidity',
unit: '%'
},
{
label: '风速',
prop: 'windSpeed',
unit: 'm/s'
},
{
label: '风向',
prop: 'windDirect',
unit: ''
},
{
label: '大气压',
prop: 'pressure',
unit: 'hPa'
},
{
label: '降水量',
prop: 'rainFall',
unit: 'mm'
},
{
label: '光照度',
prop: 'illuminance',
unit: 'Lux'
},
{
label: '当前时间',
prop: 'createTime'
}
]
const weatherModel = {
deepSiteCode: 0,
temperature: 0,
humidity: 0,
windSpeed: 0,
windDirect: 0,
pressure: 0,
rainFall: 0,
illuminance: 0,
createTime: null
}
const items = ref([])
const model = reactive({})
const init = () => {
if(data.value.videoType === '航道流速设备') {
items.value = velocityItems
const params = {
waterwayVelocity: data.value.id
}
// getWaterwayVelocity(params).then(res => {
// Object.keys(velocityModel).forEach(key => {
// if(key === 'createTime') {
// model[key] = dayjs().format('YYYY-MM-DD HH:mm:ss')
// }else{
// model[key] = res.result[key]
// }
// })
// })
}else if(data.value.videoType === '气象观测站设备') {
items.value = weatherItems
const params = {
waterwayVelocity: data.value.id
}
// getWaterwayWeather(params).then(res => {
// Object.keys(weatherModel).forEach(key => {
// if(key === 'createTime') {
// model[key] = dayjs().format('YYYY-MM-DD HH:mm:ss')
// }else{
// model[key] = res.result[key]
// }
// })
// })
}
}
watch(() => data.value, () => {
init()
}, { immediate: true })
</script>
<style lang="scss" scoped>
.content-wrapper {
width: 100%;
// height: 300px;
overflow: auto;
.list-wrapper {
width: 100%;
display: flex;
flex-direction: column;
gap: 8px;
.list-item {
width: 100%;
display: flex;
height: 18px;
align-items: center;
.label {
width: 120px;
font-size: 14px;
color: #00C0FFFF;
text-align: left;
}
.value {
color: #FFFFFFFF;
font-size: 14px;
}
}
.subtitle {
width: 100%;
height: 28px;
background-color: #00C0FF33;
color: #00C0FFFF;
font-size: 14px;
display: flex;
justify-content: space-between;
align-items: center;
padding: 0 4px;
box-sizing: border-box;
&::after {
content: '';
display: block;
width: 14px;
height: 14px;
background-image: url('@/assets/images/common/icon-triangle.png');
background-size: 100% 100%;
background-repeat: no-repeat;
}
}
}
}
</style>

View File

@@ -0,0 +1,175 @@
<template>
<div class="content-wrapper">
<div class="monitor-cctv video-windowcctv">
<HikPlayerComponent ref="HikCCTV" v-if="visible" :cameraIndexCode="data.videoCode" id="cctv"/>
</div>
</div>
</template>
<script setup>
import { computed, nextTick, onMounted, ref } from 'vue'
import useMapStore from '@/store/modules/map'
import HikPlayerComponent from '@/components/Player/HikPlayer.vue'
const mapStore = useMapStore()
const visible = ref(false)
const data = computed(() => mapStore.windowInfo.data)
const HikCCTV = ref(null)
onMounted(() => {
nextTick(() => {
visible.value = true
})
})
defineExpose({
HikCCTV
})
</script>
<style lang="scss" scoped>
.content-wrapper {
width: 100%;
height: 100%;
overflow: auto;
.list-wrapper {
width: 100%;
display: flex;
flex-direction: column;
gap: 8px;
.list-item {
width: 100%;
display: flex;
height: 18px;
align-items: center;
.label {
width: 100px;
font-size: 14px;
color: #00C0FFFF;
text-align: left;
}
.value {
color: #FFFFFFFF;
font-size: 14px;
}
}
.subtitle {
width: 100%;
height: 28px;
background-color: #00C0FF33;
color: #00C0FFFF;
font-size: 14px;
display: flex;
justify-content: space-between;
align-items: center;
padding: 0 4px;
box-sizing: border-box;
&::after {
content: '';
display: block;
width: 14px;
height: 14px;
background-image: url('@/assets/images/common/icon-triangle.png');
background-size: 100% 100%;
background-repeat: no-repeat;
}
}
.title{
position: relative;
.button{
position: absolute;
right: 0;
top: -32px;
cursor: pointer;
color: #00c0ff;
padding: 6px 10px;
background: rgba(22, 119, 255, 0.21);
border-radius: 2px 2px 2px 2px;
border: 1px solid #236ACE;
color: rgba(255, 255, 255, 0.9);
}
}
}
.list-wrapper {
width: 100%;
height: calc(100% - 50px);
margin-top: 10px;
overflow: auto;
.header{
width: 100%;
height: 40px;
background: linear-gradient( 0deg, rgba(10,167,255,0) 0%, rgba(22,115,255,0.5) 100%);
border-radius: 3px 3px 0px 0px;
display: flex;
.header-label{
font-size: 12px;
color: #F4F9FECC;
flex-shrink:0;
display: flex;
justify-content: center;
align-items: center;
}
}
.list {
width: 100%;
height: calc(100% - 50px);
overflow: auto;
.header{
width: 100%;
height: 40px;
background: linear-gradient( 0deg, rgba(10,167,255,0) 0%, rgba(22,115,255,0.5) 100%);
border-radius: 3px 3px 0px 0px;
display: flex;
.header-label{
font-size: 12px;
color: #F4F9FECC;
flex-shrink:0;
display: flex;
justify-content: center;
align-items: center;
}
}
.item{
width: 100%;
height: 36px;
display: flex;
.row{
position: relative;
font-size: 12px;
color: #fff;
flex-shrink:0;
display: flex;
justify-content: center;
align-items: center;
}
&:nth-of-type(odd){
background: #2a64bb2b;
}
&:hover{
background-image: url('@/assets/images/common/row-background-active.png');
background-size: 100% 100%;
background-repeat: no-repeat;
.row.index::before{
background: linear-gradient( 89deg, #00F0FF 0%, rgba(4,114,217,0) 100%);
}
}
}
}
}
}
.monitor-cctv{
height: 289px;
width: 100%;
}
</style>=>

View File

@@ -0,0 +1,322 @@
<template>
<!-- 渔船信息 弹窗 -->
<DialogComponent v-if="visible && info" :title="data.boatName" width="450" :draggable="true" :modal="false" :btn="true" @handle="handleTrack" @close="closeInfo">
<div class="content-wrapper">
<ul class="list-wrapper">
<li class="list-item" v-for="item in columns" :key="item.prop">
<span class="label">{{item.label}}</span>
<span class="value">{{data[item.prop]}}{{ item.unit }}</span>
</li>
<div class="subtitle">监控列表</div>
<div class="row" v-for="item in monitors" :key="item.videoName">
<div class="left">
<img src="@/assets/images/map/devices/icon-monitor.png" alt="">
<span class="name" :title="item.videoName">{{ item.videoName }}</span>
<span class="distance">{{item.distance}}km</span>
</div>
<div class="button" @click="handleFollow(item)">
<img src="@/assets/images/map/devices/icon-view.png" alt="">
光电联动
</div>
</div>
</ul>
</div>
</DialogComponent>
<!-- 光电随动视频 -->
<DialogComponent class="monitor-follow-dialog" v-if="visible && monitor.visible" :title="monitor.data.videoName" width="450" :draggable="true" :modal="false" @close="closeMonitor" @mousedown="drag">
<div class="monitor-follow video-windowfollow">
<HikPlayerComponent ref="HikFollow" v-if="monitor.data&&monitor.data.url" :cameraIndexCode="monitor.data.url" id="follow"/>
</div>
</DialogComponent>
</template>
<script setup>
import { computed, nextTick, reactive, ref, watch } from 'vue'
import DialogComponent from '@/components/Dialog/screen.vue'
import HikPlayerComponent from '@/components/Player/HikPlayer.vue'
import { findAISPointPositionByMmsi, getDevicesForServo, getDevicesIsCover, sitMoveByGps, servoByRadar, exitServoByRadar } from '@/api/map'
import { dragEvent } from '@/utils/common'
import GlobalMap from '@/components/map/js/GlobalMap'
import ShipPathInMap from '@/components/map/js/ShipPathInMap'
import useMapStore from '@/store/modules/map'
const mapStore = useMapStore()
const visible = computed(() => mapStore.windowInfo.visible)
const type = computed(() => mapStore.windowInfo.type)
const data = computed(() => mapStore.windowInfo.data)
const info = ref(true)
const monitor = reactive({
visible: true,
data: {}
})
const columns = [
{
label: 'AIS编号',
prop: 'terminalCode'
},
{
label: '船牌号',
prop: 'boatName'
},
{
label: '航速',
prop: 'sog',
unit: '节'
},
{
label: '航向',
prop: 'angle',
unit: '度'
}
]
const monitors = ref([])
const HikFollow = ref(null)
// 光电随动控制标识
const currentServo = ref('')
let globalMap = null
/**
* 拖拽事件
* @param e
*
*/
const drag = (e) => {
dragEvent(e, 'el-dialog', () => {
HikFollow.value.initResize(false)
})
}
const getMonitorList = () => {
const params = {
gpsX: data.value.longitude,
gpsY: data.value.latitude
}
getDevicesForServo(params).then(res => {
monitors.value = res.data
if(res.data.length > 0) {
// 光电联动 默认预览第一个监控视频
handleFollow(res.data[0])
}
})
}
const closeInfo = () => {
info.value = false
if(!monitor.visible) {
close()
}
}
const closeMonitor = () => {
monitor.visible = false
monitor.data = {}
if(!info.value) {
close()
}
// 退出随动
if(currentServo.value) {
handleExitServo()
}
}
const close = () => {
mapStore.updateWindowInfo(false)
}
// 判断监控设备和将要联动的定位目标是否超出可视范围、是否处于视角遮挡区
const handleFollow = (item) => {
const params = {
deviceCode: item.videoCode,
gpsX: data.value.longitude,
gpsY: data.value.latitude
}
getDevicesIsCover(params).then(res => {
if (res.msg.includes('超出')) {
ElMessage.warning(res.msg)
}
handleSitMoveByGps(item)
})
}
// 联动控制
const handleSitMoveByGps = (item) => {
closeMonitor()
const params = {
deviceCode: item.videoCode,
terminalCode: data.value.terminalCode,
gpsX: data.value.longitude,
gpsY: data.value.latitude
}
sitMoveByGps(params).then(res => {
if (res.code === 200) {
monitor.visible = true
nextTick(() => {
monitor.data.videoName = item.videoName
monitor.data.url = item.videoCode
})
}
// 光电随动控制
handleServoByRadar(item)
})
}
// 光电随动
const handleServoByRadar = (item) => {
const params = {
deviceCode: item.videoCode,
terminalCode: data.value.terminalCode,
gpsX: data.value.longitude,
gpsY: data.value.latitude
}
servoByRadar(params).then(res => {
if (res.code === 200) {
currentServo.value = data.value.terminalCode
}
})
}
// 退出随动
const handleExitServo = () => {
const params = {
terminalCode: currentServo.value
}
exitServoByRadar(params).then(res => {
if (res.code === 200) {
currentServo.value = ''
}
})
}
/**
* 格式化轨迹数据
* @param data 原始数据
* @return {Array}
*/
const formatTrackData = (data) => {
const list = []
const trackObj = data.map((_item) => {
const info = { ..._item }
info.longitude = Number(_item.longitude.toFixed(6))
info.latitude = Number(_item.latitude.toFixed(6))
info.time = new Date(_item.gpsTime).getTime()
return info
}).filter((point) => Math.abs(point.latitude) < 90 && Math.abs(point.longitude) < 180)
list.push(trackObj)
return list
}
// 查询轨迹
const handleTrack = () => {
globalMap = GlobalMap.instance
findAISPointPositionByMmsi({ mmsi: data.value.terminalCode }).then(res => {
if (res.success) {
const arr = res.result[data.value.terminalCode]
new ShipPathInMap(globalMap.map, globalMap.map.getLayer('track'), formatTrackData(arr))
}
}).finally(() => {
mapStore.updateWindowInfo(false)
})
}
watch(() => data.value, () => {
if(type.value === '_trawler_dynamic') {
info.value = true
getMonitorList()
}else{
info.value = false
monitor.visible = false
}
})
</script>
<style lang="scss">
.content-wrapper {
width: 100%;
overflow: auto;
.list-wrapper {
width: 100%;
display: flex;
flex-direction: column;
gap: 8px;
.list-item {
width: 100%;
display: flex;
height: 18px;
align-items: center;
.label {
width: 100px;
font-size: 14px;
color: #00C0FFFF;
text-align: left;
}
.value {
color: #FFFFFFFF;
font-size: 14px;
}
}
.subtitle {
width: 100%;
height: 28px;
background-color: #00C0FF33;
color: #00C0FFFF;
font-size: 14px;
display: flex;
justify-content: space-between;
align-items: center;
padding: 0 4px;
box-sizing: border-box;
&::after {
content: '';
display: block;
width: 14px;
height: 14px;
background-image: url('@/assets/images/common/icon-triangle.png');
background-size: 100% 100%;
background-repeat: no-repeat;
}
}
.row{
display: flex;
justify-content: space-between;
.name{
color: rgba(0, 192, 255, 1);
margin: 0 5px;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
min-width: 0;
}
.distance{
color: rgba(255, 255, 255, 1);
}
.left{
display: flex;
flex: 1;
align-items: center;
min-width: 0;
}
.button{
color: rgba(0, 246, 255, 1);
display: flex;
align-items: center;
cursor: pointer;
img{
margin-right: 2px;
}
}
}
}
}
.monitor-follow-dialog{
margin-left: calc(50% + 225px) !important;
.el-dialog__body{
padding: 0 !important;
}
.monitor-follow{
height: 289px;
width: 100%;
}
}
</style>

View File

@@ -0,0 +1,219 @@
<template>
<div class="content-wrapper">
<div class="left-wrapper">
<div class="uav-button" @click="handleAlgorithm">{{algorithmStatus ? '关闭' : '开启'}}算法</div>
<div class="Form">
<el-checkbox-group v-model="algorithmValue">
<el-checkbox
v-for="item in algorithms"
:key="item.value"
:label="item.label"
:value="item.value" />
</el-checkbox-group>
</div>
<div class="flv-container"><FlvPlayerComponent v-if="uavDialog.url" id="uav" :url="uavDialog.url"/></div>
</div>
<div class="resize-handle" @mousedown="startResize"></div>
<div class="right-wrapper">
<CockpitCom v-if="uavDialog.visible"/>
</div>
</div>
</template>
<script setup>
import { computed, reactive, ref } from 'vue'
import useMapStore from '@/store/modules/map'
import FlvPlayerComponent from '@/components/FlvPlayer/index.vue'
import CockpitCom from '@/views/business/drone/cockpit.vue'
const mapStore = useMapStore()
const data = computed(() => mapStore.windowInfo.data)
// 算法开启关闭状态
const algorithmStatus = ref(false)
const algorithms = [
{ value: 120000, label: 'AIS挂牌/船牌识别' },
{ value: 140000, label: '船型识别' },
{ value: 139000, label: '未穿救生衣' },
{ value: 140009, label: '未悬挂国旗' },
{ value: 140008, label: '未封舱' }
]
const algorithmValue = ref([])
const uavDialog = reactive({
visible: false,
url: ''
})
// 添加分割线相关的响应式数据
const isResizing = ref(false)
const leftWidth = ref('462px')
const rightWidth = ref('1391px')
const containerWidth = ref(0)
let containerBoundsLeft = 0 // 容器左边界
// 开启/关闭算法
const handleAlgorithm = () => {
if(algorithmStatus.value) {
closeAlgorithm()
} else {
let enable_orc = false
const valueArray = [ ...algorithmValue.value ]
const index = valueArray.indexOf(120000)
if (index > -1) {
valueArray.splice(index, 1)
enable_orc = true
}
const params = {
class_codes: valueArray.join(','),
enable_orc,
status: 'start',
sn: data.value.droneSn
}
// doStartOrStopUavAlgorithm(params).then(res => {
// if(res.success) {
// algorithmStatus.value = true
// ElMessage.success('算法已开启')
// }else {
// ElMessage.error(res.result)
// }
// })
}
}
// 添加分割线控制相关方法
const startResize = (e) => {
isResizing.value = true
const containerRect = e.target.parentElement.getBoundingClientRect()
containerWidth.value = containerRect.width
// 保存容器的左边界位置
containerBoundsLeft = containerRect.left
document.addEventListener('mousemove', resize)
document.addEventListener('mouseup', stopResize)
}
const resize = (e) => {
if (isResizing.value) {
// 使用预先保存的容器左边界
const offsetX = e.clientX - containerBoundsLeft
// 计算左侧宽度百分比
let leftPercent = offsetX / containerWidth.value * 100
// 限制左右两侧的最小宽度
const minRightWidth = 1391
const minLeftWidth = 200
// 计算右侧最小百分比
const minRightPercent = minRightWidth / containerWidth.value * 100
const minLeftPercent = minLeftWidth / containerWidth.value * 100
// 限制拖动范围
if (leftPercent < minLeftPercent) {
leftPercent = minLeftPercent
} else if (leftPercent > 100 - minRightPercent) {
leftPercent = 100 - minRightPercent
}
leftWidth.value = `${leftPercent}%`
rightWidth.value = `${100 - leftPercent}%`
}
}
const stopResize = () => {
isResizing.value = false
document.removeEventListener('mousemove', resize)
document.removeEventListener('mouseup', stopResize)
}
</script>
<style lang="scss" scoped>
// 无人机弹窗
.content-wrapper{
display: flex;
position: relative;
height: 100%;
video{
width: 100%;
height: 830px;
object-fit: fill;
}
// //播放按钮
video::-webkit-media-controls-play-button{display: none;}
//进度条
video::-webkit-media-controls-timeline{display: none;}
//观看的当前时间
video::-webkit-media-controls-current-time-display{display: none;}
//剩余时间
video::-webkit-media-controls-time-remaining-display{display: none;}
//音量按钮
video::-webkit-media-controls-mute-button{display: none;}
video::-webkit-media-controls-toggle-closed-captions-buttonf{display: none;}
//1音量的控制条
video::-webkit-media-controls-volume-slider{display: none;}
video::-webkit-media-controls-enclosuret{display: none;}
.uav-button{
width: fit-content;
cursor: pointer;
color: #00c0ff;
padding: 6px 10px;
background: rgba(22, 119, 255, 0.21);
border-radius: 2px 2px 2px 2px;
border: 1px solid #236ACE;
color: rgba(255, 255, 255, 0.9);
}
.left-wrapper{
// width: 60%;
width: v-bind(leftWidth);
height: 830px;
display: flex;
flex-direction: column;
gap: 10px;
.el-checkbox-group{
gap: 4px !important;
.el-checkbox{
width: 150px !important;
padding-left: 5px !important;
}
}
.flv-container{
flex: 1; // 占据剩余空间
overflow: hidden; // 隐藏溢出内容
}
}
.resize-handle {
width: 8px;
height: 100%;
background: transparent;
cursor: col-resize;
position: relative;
user-select: none;
z-index: 10;
&::after {
content: "";
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 2px;
// height: 40px;
background: #fff;
}
&:hover {
background: transparent;
}
}
.right-wrapper{
// width: 40%;
width: v-bind(rightWidth);
height: 830px;
// position: absolute;
// right: 0;
flex: 1;
}
.temporary{
position: absolute;
right: 0'';
right: 0;
top: 48px;
z-index: 999;
width: 1069px;
height: 429px;
}
}
</style>