<!--当前任务详情-->
|
<template>
|
<div
|
class="content-container"
|
ref="monitorRef"
|
:class="{ landscapeMode, showBottomLeftCorner }"
|
v-if="isShow"
|
v-loading="dialogLoading"
|
element-loading-text="加载中..."
|
element-loading-background="rgb(33 33 33 / 80%)"
|
>
|
<!-- 视频直播 -->
|
<div :class="`${isMaxMap ? 'minBox' : 'maxBox'} ${liveSuccess ? 'centerPoint' : ''}`" id="liveVideoBox">
|
<LiveVideo
|
v-if="liveSuccess"
|
:videoUrl="currentLiveUrl"
|
:controls="false"
|
:hasRightMenu="true"
|
:camera_type="cameraParams.camera_type"
|
:liveFullScreen="liveFullScreen"
|
@video-click="() => isMaxMap && switchMapSize()"
|
/>
|
<div v-else class="liveErr">
|
<div class="liveErrBg" />
|
</div>
|
</div>
|
<RealTimeMap
|
@click="() => !isMaxMap && switchMapSize()"
|
ref="realTimeMap"
|
:class="`${isMaxMap ? 'maxBox' : 'minBox'}`"
|
v-if="taskWayLineDetails?.[0]?.url"
|
/>
|
<TaskDetailsHead v-if="showHead" />
|
<AppPtzControl v-if="isCurFlightTask"/>
|
<AppConsoleLeft v-if="isTakeOff && !showBottomLeftCorner && isCurFlightTask" />
|
<AppConsoleRight v-if="isTakeOff && isCurFlightTask" />
|
<div class="smallWindowArrow">
|
<img alt="" :src="xzsSvg" @click="switchShowSmallWindow" />
|
</div>
|
</div>
|
</template>
|
|
<script setup>
|
import LiveVideo from '@/components/LiveVideo.vue'
|
import { getDeviceDetail, liveStart } from '@/api/home/machineNest'
|
import RealTimeMap from '@/components/CurrentTaskDetails/RealTimeMap.vue'
|
import TaskDetailsHead from '@/components/CurrentTaskDetails/TaskDetailsHead.vue'
|
import amplifyImg from '@/assets/images/taskManagement/taskIntermediateContent/amplifySvg.svg'
|
import gdSvg from '@/appDataSource/inspectionTask/droneConsole/高度.svg'
|
import sdSvg from '@/appDataSource/inspectionTask/droneConsole/速度.svg'
|
import fsSvg from '@/appDataSource/inspectionTask/droneConsole/风速.svg'
|
import dcSvg from '@/appDataSource/inspectionTask/droneConsole/电池.svg'
|
import xhSvg from '@/appDataSource/inspectionTask/droneConsole/信号.svg'
|
import xzsSvg from '@/appDataSource/inspectionTask/droneConsole/xzs.svg'
|
import EventBus from '@/utils/eventBus'
|
import { updateDroneQualityApi, viewTheRecording } from '@/api/drc'
|
import {
|
getCameraInfoApi,
|
getDevicePsdkInfoApi,
|
getLiveAiLinkApi,
|
getLiveStatusApi,
|
getLoadInfoApi,
|
openSendWsApi,
|
} from '@/api/payload'
|
import { CURRENT_CONFIG } from '@/utils/http/config'
|
import { useDroneWS } from '@/hooks/useDroneWS'
|
import { useTaskDetails } from '@/hooks/useTaskDetails/useTaskDetails'
|
import { DRONE_LIST, EModeText } from '@/const/device'
|
import { useRunOnce } from '@/hooks'
|
import _ from 'lodash'
|
import { useStore } from 'vuex'
|
import AppConsoleLeft from '@/components/CurrentTaskDetails/AppConsoleLeft.vue'
|
import AppPtzControl from '@/components/CurrentTaskDetails/AppPtzControl.vue'
|
import AppConsoleRight from '@/components/CurrentTaskDetails/AppConsoleRight/AppConsoleRight.vue'
|
import { showToast } from 'vant'
|
import {getJobWayLineDetails} from '@ztzf/apis'
|
import { getJobDetails, getJobsByJobInfoIdApi } from '@/api/home/task'
|
|
// 获取详情后的回调
|
const getDetailsCallBack = async () => {
|
const dockInfoRes = await getDeviceDetail(dockSn.value)
|
const result = dockInfoRes.data.data
|
const isDockLive = [undefined, 0, 14, -1].includes(result?.children?.mode_code)
|
isTakeOff.value = !isDockLive
|
droneModelText.value = result?.children?.device_name
|
if (isDockLive) {
|
await getDeviceLiveUrl()
|
return
|
}
|
isCurFlightTask.value ? await getDroneLiveUrl(false, result.child_device_sn) : await getDeviceLiveUrl()
|
}
|
const landscapeMode = inject('landscapeMode')
|
const store = useStore()
|
// 不要随意更换顺序,有联动
|
const infoList = ref([
|
{ index: 0, title: '实时真高', value: 0, unit: 'M', hide: true },
|
{ index: 1, title: '绝对高度', value: 0, unit: 'M', img: gdSvg },
|
{ index: 2, title: '水平速度', value: 0, unit: 'M/S', img: sdSvg },
|
{ index: 3, title: '风速', value: 0, unit: 'M/S', img: fsSvg },
|
{ index: 4, title: '4G信号', value: '-', unit: '', img: xhSvg },
|
{ index: 5, title: 'SDR信号', value: '-', unit: '', hide: true },
|
{ index: 6, title: '电池电量', value: 0, unit: '%', img: dcSvg },
|
])
|
const monitorRef = ref(null)
|
const isShow = defineModel('show') // 是否显示当前任务详情
|
// const props = defineProps(['wayLineJobInfoId', 'waylineJobId', 'selectDockSn'])
|
const props = defineProps({
|
wayLineJobInfoId: { type: Number, default: null },
|
selectDockSn: { type: String, default: null },
|
// 批次id跟周期性任务有关
|
batchNo: { default: null}
|
})
|
const dockSn = computed(() => props?.selectDockSn) //机巢sn
|
const droneSn = computed(() => wsInfo.value?.device_osd?.data?.sn) //无人机sn
|
const currentMinJob = ref(null) //当前小任务信息
|
const isCurFlightTask = ref(false) //是否是当前飞行任务
|
const lineQuality = ref(1) //1流畅,2标清
|
const taskDetailsViewer = shallowRef(null) //地图实例
|
const trueAltitude = ref('') // 真实高度
|
const isAiLive = ref(false) // 是ai直播
|
const video_id = ref('') // 直播视频id
|
const currentLiveUrl = ref('') // 当前直播地址
|
const isMaxMap = ref(false) //是大地图
|
const client_id = ref('') //mqtt id
|
const hasIr = ref(false) //有红外能力
|
const isAutoControl = ref(true) //是否自动控制
|
const showUpKeyPanel = ref(false) //显示按键面板
|
const isTakeOff = ref(false) // 是在飞行中
|
const isBackDock = ref(false) //是返航
|
const activeSlider = ref(false) //变焦滑块在活动
|
const isRecording = ref(false) //是录像
|
const searchlightMode = ref(0) //探照灯模式
|
// const showHead = computed(() => !isMaxMap.value || showUpKeyPanel.value || !(isAutoControl.value || isBackDock.value)) //显示头部
|
const showHead = ref(true) //显示头部
|
const cameraParams = ref({ zoom_factor: 0, camera_type: 'wide', hasVisable: false }) //相机参数
|
let taskDetails = ref({})
|
const taskWayLineDetails = ref([])
|
let workspace_id = ref(null)
|
const currentWayLine = computed(
|
() =>
|
taskWayLineDetails?.value?.find(item => item.device_sn === props?.selectDockSn) ||
|
taskWayLineDetails?.value?.[0]
|
)
|
const isRouteRecord = ref(false) //是航线录制
|
const recordingId = ref('') //航线录制id
|
const recordingTime = ref('00:00:00') //录像时间
|
const irModeStyleType = ref(null) //红外模式样式Type
|
const dialogLoading = ref(false) //转圈加载
|
const aiLoading = ref(false) //ai按钮转圈加载
|
const showKeyRemark = ref(false) //快捷键弹框
|
const showFunBlock = ref(true) //显示功能模块
|
const droneModel = ref(null) //无人机型号 67 91 100
|
const hasAiTypeStr = computed(() => !!taskDetails.value?.ai_type_str)//有算法
|
const loadDevice = ref({}) //负载设备信息
|
const liveFullScreen = ref(true) //默认全屏
|
const canReceive = ref(true) //能接收 一个辅助变量
|
const droneModelText = ref('')
|
const isManualControl = ref(false) //当前状态是手控
|
const usedControl = ref(false) //是否使用过手动控制
|
const apiDisable = ref(false) //api禁用
|
const liveSuccess = ref(true) //直播正常
|
const debounceCanReceive = _.debounce(() => (canReceive.value = true), 4000)
|
const realTimeMap = ref(null)
|
const showBottomLeftCorner = ref(false) //显示左下角
|
const speakerInfo = ref({
|
play_volume: 80,
|
play_mode: 0, //{"0":"单次播放","1":"循环播放(单曲)"}
|
work_mode: 0, //{"0":"TTS 负载模式","1":"录音喊话"}
|
//{"0":"空闲中","1":"传输中(机场到飞行器)","2":"播放中","3":"异常中","4":"TTS 文本转换中","99":"下载中(机场从云端下载)"}
|
system_state: 0, //这个不准
|
})
|
|
// 延迟接收--四秒后自动恢复
|
const delayedRecepAuto = () => {
|
canReceive.value = false
|
debounceCanReceive()
|
}
|
|
let { wsInfo } = useDroneWS(workspace_id) //ws信息,是一个ref对象
|
const hasPayloadControl = ref(false) // 有控制权限
|
const droneStatus = ref({
|
mode_code: undefined,
|
text: undefined,
|
})
|
const zoomFactor = ref({
|
ir: { max: 0, min: 0 },
|
zoom: { max: 0, min: 0 },
|
})
|
|
provide('speakerInfo', speakerInfo)
|
provide('isCurFlightTask', isCurFlightTask)
|
provide('showBottomLeftCorner', showBottomLeftCorner)
|
provide('currentWayLine', currentWayLine)
|
provide('recordingId', recordingId)
|
provide('infoList', infoList)
|
provide('apiDisable', apiDisable)
|
provide('usedControl', usedControl)
|
provide('isTakeOff', isTakeOff)
|
provide('droneModelText', droneModelText)
|
provide('delayedRecepAuto', delayedRecepAuto)
|
provide('canReceive', canReceive)
|
provide('liveFullScreen', liveFullScreen)
|
provide('loadDevice', loadDevice)
|
provide('showUpKeyPanel', showUpKeyPanel)
|
provide('hasAiTypeStr', hasAiTypeStr)
|
provide('droneModel', droneModel)
|
provide('showKeyRemark', showKeyRemark)
|
provide('showFunBlock', showFunBlock)
|
provide('aiLoading', aiLoading)
|
provide('dialogLoading', dialogLoading)
|
provide('irModeStyleType', irModeStyleType)
|
provide('recordingTime', recordingTime)
|
provide('isRouteRecord', isRouteRecord)
|
provide('searchlightMode', searchlightMode)
|
provide('isRecording', isRecording)
|
provide('zoomFactor', zoomFactor)
|
provide('droneStatus', droneStatus)
|
provide('wsInfo', wsInfo)
|
provide('hasPayloadControl', hasPayloadControl)
|
provide('cameraParams', cameraParams)
|
provide('isMaxMap', isMaxMap)
|
provide('isBackDock', isBackDock)
|
provide('workspace_id', workspace_id)
|
provide('dockOsdInfo', wsInfo?.value?.dock_osd)
|
provide('dockSn', dockSn)
|
provide('droneSn', droneSn)
|
provide('isAutoControl', isAutoControl)
|
provide('isManualControl', isManualControl)
|
provide('lineQuality', lineQuality)
|
provide('taskDetailsViewer', taskDetailsViewer)
|
provide('taskDetails', taskDetails)
|
provide('taskWayLineDetails', taskWayLineDetails)
|
provide('trueAltitude', trueAltitude)
|
provide('isAiLive', isAiLive)
|
provide('video_id', video_id)
|
provide('client_id', client_id)
|
provide('hasIr', hasIr)
|
provide('showHead', showHead)
|
provide('activeSlider', activeSlider)
|
|
const userId = computed(() => store.state.user.userInfo.user_id)
|
|
// 获取机巢直播
|
const getDeviceLiveUrl = async () => {
|
try {
|
const res = await liveStart(dockSn.value, 2)
|
currentLiveUrl.value = res.data.data.rtcs_url
|
video_id.value = null
|
liveSuccess.value = true
|
} catch (e) {
|
liveSuccess.value = false
|
}
|
}
|
|
// set Ai直播url
|
const getAiLiveUrl = async () => {
|
if (!video_id.value) return showToast('无人机未起飞,无法开启AI识别')
|
if (!isCurFlightTask.value) return
|
aiLoading.value = true
|
try {
|
const res = await getLiveAiLinkApi({
|
original_stream_url: `${CURRENT_CONFIG.rtmpURL}${video_id.value.replace(/\//g, '-')}`,
|
video_id: video_id.value,
|
})
|
currentLiveUrl.value = res.data.data.rtcs_url
|
showToast('开启成功')
|
openSendWsApi(droneSn.value, { type: 'AI' }, { open: true, user_id: userId.value })
|
isAiLive.value = true
|
} catch (e) {}
|
aiLoading.value = false
|
}
|
|
// 获取无人机直播url
|
async function getDroneLiveUrl(reset = false, sn) {
|
try {
|
delayedRecepAuto()
|
currentLiveUrl.value = ''
|
await nextTick()
|
const res = await liveStart(sn || droneSn.value, lineQuality.value)
|
currentLiveUrl.value = res.data.data.rtcs_url
|
video_id.value = res.data.data.video_id
|
isAiLive.value = false
|
reset && showToast('刷新成功')
|
liveSuccess.value = true
|
} catch (e) {
|
liveSuccess.value = false
|
}
|
}
|
|
// 无人机直播画质切换
|
const changeLineQuality = async () => {
|
await updateDroneQualityApi({ video_id: video_id.value, video_quality: lineQuality.value })
|
showToast('切换画质成功')
|
}
|
|
// 设置当前直播地址
|
const setCurrentLiveUrl = async () => {
|
const deviceInfo = wsInfo.value?.device_osd?.data?.host
|
if (!deviceInfo) return
|
const currentIsTakeOff = ![14, 0].includes(deviceInfo?.mode_code)
|
// 如果还是之前的状态,不切换
|
if (isTakeOff.value === currentIsTakeOff) return
|
isTakeOff.value = currentIsTakeOff
|
isTakeOff.value && isCurFlightTask.value ? await getDroneLiveUrl() : await getDeviceLiveUrl()
|
}
|
|
// 获取相机信息,只会触发一次
|
const getCameraInfo = useRunOnce(() => {
|
getCameraInfoApi(droneSn.value, 1).then(res => {
|
res.data?.data?.forEach(item => {
|
if (item.camera_mode === 4) {
|
cameraParams.value.hasVisable = !!item.is_storage
|
}
|
if (item.camera_mode === 3 && item.is_storage) {
|
hasIr.value = true
|
}
|
if ([2, 3].includes(item.camera_mode)) {
|
const field = item.camera_mode === 3 ? 'ir' : 'zoom'
|
zoomFactor.value[field].max = _.round(item.zoom_factor_max, 0)
|
zoomFactor.value[field].min = _.round(item.zoom_factor_min, 0)
|
if (field === 'zoom') {
|
// 设置广角默认值
|
cameraParams.value.zoom_factor = _.round(item.zoom_factor_min - 1, 0)
|
}
|
}
|
})
|
})
|
})
|
|
// 获取当前psdk信息
|
const getDevicePsdkInfo = useRunOnce(() => {
|
getDevicePsdkInfoApi(droneSn.value).then(res => {
|
const psdkInfo = res?.data?.data?.psdk_widget_values
|
const speaker = psdkInfo?.[0]?.speaker
|
if (speaker) {
|
speakerInfo.value = speaker
|
}
|
getDevicePsdkInfoWs(psdkInfo)
|
})
|
})
|
|
function switchMapSize() {
|
isMaxMap.value = !isMaxMap.value
|
nextTick(() => {
|
realTimeMap?.value?.mapReset()
|
})
|
}
|
function switchShowSmallWindow() {
|
showBottomLeftCorner.value = !showBottomLeftCorner.value
|
nextTick(() => {
|
realTimeMap?.value?.mapReset()
|
})
|
}
|
|
// 获取实时psdk信息
|
const getDevicePsdkInfoWs = psdkInfoList => {
|
if (psdkInfoList) {
|
const findSpeaker = psdkInfoList?.find(item => item.psdk_index === 2)
|
const findSearchlight = psdkInfoList?.find(item => item.psdk_name === 'Searchlight')
|
if (findSpeaker) {
|
if (!findSearchlight) {
|
}
|
}
|
if (findSearchlight) {
|
}
|
}
|
}
|
|
// 设置相机类型和清晰度
|
const setLiveStatusWs = live_status => {
|
if (live_status) {
|
cameraParams.value.camera_type = live_status?.video_type || 'wide'
|
lineQuality.value = live_status?.video_quality || 1
|
}
|
}
|
|
// 获取当前相机类型和视频清晰度
|
const getLiveStatusRunOnce = useRunOnce(() => {
|
getLiveStatusApi(dockSn.value).then(res => {
|
const live_status = res.data?.data?.live_status?.[0]
|
setLiveStatusWs(live_status)
|
})
|
})
|
|
// 获取无人机负载设备信息
|
const getLoadInfoRunOnce = useRunOnce(() => {
|
getLoadInfoApi(dockSn.value).then(res => {
|
loadDevice.value = res.data?.data || {}
|
})
|
})
|
// 获取信息航线是否录制
|
const getviewTheRecording = useRunOnce(() => {
|
viewTheRecording({ sn: dockSn.value }).then(res => {
|
isRouteRecord.value = res.data.data ? true : false
|
recordingId.value = res.data.data.id
|
// console.log('获取信息', res.data.data)
|
})
|
})
|
// 开启ai识别
|
const openAiRunOnce = useRunOnce(getAiLiveUrl)
|
|
// 统一节流处理
|
const wsInfoChangeThrottle = _.throttle(wsInfo => {
|
const { mode_code, payloads } = wsInfo.value?.device_osd?.data?.host || {}
|
const { sub_device } = wsInfo.value?.dock_osd?.data?.host || {}
|
const { ai, searchlight } = wsInfo.value?.web_request_send_ws?.data || {}
|
const live_status = wsInfo.value?.live_status?.data?.live_status
|
const speaker = wsInfo.value?.psdk_widget_values?.data?.psdk_widget_values?.[0]?.speaker
|
|
if (canReceive.value) {
|
searchlightMode.value = searchlight?.value || 0
|
if (ai?.open && !isAiLive.value && ai?.user_id === userId.value) {
|
openAiRunOnce()
|
}
|
if (speaker) {
|
speakerInfo.value = speaker
|
}
|
setLiveStatusWs(live_status?.[0])
|
}
|
if (mode_code !== undefined) {
|
droneStatus.value = { text: EModeText?.[mode_code] || '--', mode_code }
|
}
|
if (sub_device?.device_model_key !== undefined) {
|
droneModel.value = DRONE_LIST.find(item => sub_device?.device_model_key?.includes(item.value))?.value
|
}
|
irModeStyleType.value = payloads?.[0]?.thermal_current_palette_style
|
getDevicePsdkInfoWs(wsInfo.value?.psdk_widget_values?.data?.psdk_widget_values)
|
}, 1000)
|
|
watch(
|
wsInfo,
|
() => {
|
setCurrentLiveUrl()
|
if (wsInfo.value?.device_osd) {
|
getCameraInfo()
|
getDevicePsdkInfo()
|
// getviewTheRecording()
|
}
|
if (wsInfo.value?.dock_osd) {
|
getLiveStatusRunOnce()
|
getLoadInfoRunOnce()
|
}
|
wsInfoChangeThrottle(wsInfo)
|
},
|
{ deep: true }
|
)
|
|
async function getTaskDetailsFun() {
|
try {
|
const minJobListRes = await getJobsByJobInfoIdApi({ jobInfoId: props.wayLineJobInfoId })
|
let minJobList = minJobListRes.data.data || []
|
if (props.batchNo !== null && props.batchNo !== undefined){
|
minJobList = minJobList.filter(item => item.batch_no === Number(props.batchNo))
|
}
|
currentMinJob.value = minJobList.find(item => item.dock_sn === props.selectDockSn)
|
|
|
console.log(currentMinJob, minJobList, props.selectDockSn, 11)
|
|
|
isCurFlightTask.value = currentMinJob.value?.status === 2
|
|
const params = {
|
wayLineJobInfoId: props.wayLineJobInfoId,
|
waylineJobId: currentMinJob.value?.id,
|
batchNo: currentMinJob.value?.batch_no,
|
}
|
|
const res = await getJobDetails(params)
|
|
const wayLineDetails = await getJobWayLineDetails({
|
...params,
|
sn: props.selectDockSn
|
})
|
|
taskWayLineDetails.value = wayLineDetails.data.data
|
|
taskDetails.value = res.data.data
|
await getDetailsCallBack()
|
workspace_id.value = currentWayLine.value?.workspace_id
|
} catch (error) {
|
console.log(error)
|
}
|
}
|
|
watch(
|
() => wsInfo.value?.flighttask_progress?.data?.bid,
|
val => {
|
const flightTaskId = currentMinJob.value.job_id
|
isCurFlightTask.value = flightTaskId ? val === flightTaskId : true
|
}
|
)
|
|
onMounted(() => {
|
getTaskDetailsFun()
|
store.commit('setConsoleShow', true)
|
EventBus.on('CurrentTaskDetails-changeLineQuality', changeLineQuality)
|
EventBus.on('CurrentTaskDetails-getAiLiveUrl', getAiLiveUrl)
|
EventBus.on('CurrentTaskDetails-getDroneLiveUrl', getDroneLiveUrl)
|
})
|
|
onBeforeUnmount(() => {
|
store.commit('setConsoleShow', false)
|
EventBus.off('CurrentTaskDetails-changeLineQuality', changeLineQuality)
|
EventBus.off('CurrentTaskDetails-getAiLiveUrl', getAiLiveUrl)
|
EventBus.off('CurrentTaskDetails-getDroneLiveUrl', getDroneLiveUrl)
|
})
|
</script>
|
|
<style lang="scss">
|
.current-task-details {
|
display: flex;
|
justify-content: space-between;
|
|
.closeOrBack {
|
position: absolute;
|
padding-left: 5px;
|
left: 0;
|
top: 14px;
|
color: #fff;
|
font-size: 35px;
|
z-index: 5001;
|
|
.el-icon {
|
cursor: pointer;
|
}
|
}
|
|
.el-dialog {
|
position: relative;
|
padding: 0;
|
|
.el-dialog__body {
|
width: 100%;
|
height: 100%;
|
}
|
|
.el-dialog__header {
|
height: 0;
|
overflow: hidden;
|
padding: 0;
|
}
|
}
|
}
|
</style>
|
|
<style lang="scss" scoped>
|
.content-container {
|
//变量
|
$minBoxWidth: half(184);
|
$minBoxHeight: half(88);
|
|
position: absolute;
|
height: 210.9375px;
|
width: 375px;
|
//height: 100%;
|
//width: 100%;
|
overflow: hidden;
|
font-size: 9px;
|
|
&.landscapeMode {
|
height: 100%;
|
width: 100%;
|
}
|
|
:deep() {
|
.whiteBtn {
|
padding: 0 half(7);
|
flex-shrink: 0;
|
height: half(38);
|
background: #ffffff;
|
border-radius: half(8);
|
font-family: Source Han Sans CN, Source Han Sans CN;
|
font-weight: 400;
|
font-size: half(13);
|
color: #171717;
|
line-height: half(38);
|
text-align: center;
|
}
|
}
|
|
#liveVideoBox{
|
.liveErr{
|
position: relative;
|
width: 100%;
|
height: 100%;
|
background: rgba(31, 31, 31, 0.6);
|
.liveErrBg{
|
position: relative;
|
width: 100%;
|
height: 100%;
|
background: url(@/assets/images/offLine.svg) no-repeat center / 80% 80%;
|
color: #ededed;
|
font-size: 16px;
|
}
|
}
|
}
|
|
&.showBottomLeftCorner {
|
.minBox {
|
visibility: visible;
|
width: $minBoxWidth;
|
height: $minBoxHeight;
|
}
|
.smallWindowArrow {
|
cursor: pointer;
|
transform: translate(0, 100%);
|
position: absolute;
|
left: calc(#{$minBoxWidth} - half(27));
|
bottom: $minBoxHeight;
|
}
|
}
|
|
.centerPoint {
|
&:before {
|
z-index: 5;
|
opacity: 0.5;
|
border-radius: 50%;
|
background-color: yellow;
|
content: '';
|
font-size: 30px;
|
position: absolute;
|
width: half(10);
|
height: half(10);
|
left: 50%;
|
top: 50%;
|
transform: translate(-50%, -50%);
|
pointer-events: none;
|
font-weight: bold;
|
text-shadow: -1px -1px 0 black, 1px -1px 0 black, -1px 1px 0 black, 1px 1px 0 black; /* 四方向描边 */
|
}
|
}
|
|
.maxBox {
|
width: 100%;
|
height: 100%;
|
}
|
|
.minBox {
|
position: absolute;
|
visibility: hidden;
|
width: $minBoxWidth;
|
height: $minBoxHeight;
|
left: 0;
|
bottom: 0;
|
z-index: 999;
|
}
|
|
.amplify {
|
cursor: pointer;
|
position: absolute;
|
background: rgba(0, 0, 0, 0.3);
|
transform: translate(0, 100%);
|
left: 0;
|
bottom: $minBoxHeight;
|
width: half(27);
|
height: half(27);
|
z-index: 999;
|
display: flex;
|
align-items: center;
|
justify-content: center;
|
border-radius: 10%;
|
> img {
|
width: half(20);
|
height: half(20);
|
}
|
}
|
|
.smallWindowArrow {
|
cursor: pointer;
|
position: absolute;
|
transform: translate(0, 50%) rotate(180deg);
|
background: rgba(0, 0, 0, 0.3);
|
left: 0;
|
bottom: calc($minBoxHeight / 2);
|
z-index: 999;
|
color: white;
|
width: half(27);
|
height: half(27);
|
display: flex;
|
align-items: center;
|
justify-content: center;
|
border-radius: 10%;
|
|
> img {
|
width: half(18);
|
height: half(18);
|
}
|
}
|
}
|
</style>
|