938 lines
24 KiB
Vue
938 lines
24 KiB
Vue
<template>
|
||
<div class="w100 h100">
|
||
<div class="tree" ref="tree">
|
||
<div class="tree-date">
|
||
<span>{{ currentDate }}</span>
|
||
<span> <i class="el-icon-location"></i>凤庆县 </span>
|
||
</div>
|
||
<div class="weather-container">
|
||
<div class="temperature">
|
||
<div class="temperature-left">
|
||
<span class="temp-value">11</span>
|
||
<span class="temp-unit">℃</span>
|
||
</div>
|
||
<div class="weather-summary">
|
||
<span>多云</span>
|
||
<span class="temperature-range">12/-1℃</span>
|
||
</div>
|
||
</div>
|
||
<div class="weather-info-grid">
|
||
<div class="weather-item">
|
||
<span class="value">东风</span>
|
||
<span class="label">3级</span>
|
||
</div>
|
||
<div class="weather-item">
|
||
<span class="value">光照</span>
|
||
<span class="label">强</span>
|
||
</div>
|
||
<div class="weather-item">
|
||
<span class="value">湿度</span>
|
||
<span class="label">85%</span>
|
||
</div>
|
||
<div class="weather-item">
|
||
<span class="value">降雨 </span>
|
||
<span class="label">0mm</span>
|
||
</div>
|
||
<div class="weather-item">
|
||
<span class="value">炉温</span>
|
||
<span class="label">1201℃</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="tree-date"></div>
|
||
<div
|
||
v-for="(item, index) in productList"
|
||
:class="`product product-${index + 1} ${currentBase === item.id ? 'on' : ''}`"
|
||
ref="product"
|
||
:key="index"
|
||
@click="openDialog(item)"
|
||
>
|
||
<div class="radiating-point">
|
||
<div class="point"></div>
|
||
<div class="wave"></div>
|
||
<div class="wave"></div>
|
||
<div class="wave"></div>
|
||
</div>
|
||
<div class="product-tips">
|
||
<img class="width-60 height-60" :src="item.imgUrl" alt="" />
|
||
<span class="product-info">
|
||
{{ item.productName }}
|
||
<!-- <em>点击查看地块信息</em> -->
|
||
</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 实时数据监测弹窗 -->
|
||
<el-dialog
|
||
class="deviceDialog"
|
||
title="设备监测控制"
|
||
:visible="true"
|
||
v-if="deviceDialogVisiable"
|
||
width="1070px"
|
||
append-to-body
|
||
@close="deviceDialogVisiable = false"
|
||
>
|
||
<!-- 设备信息和设备选择 -->
|
||
<div class="deviceInfo flex aic jcsb">
|
||
<div class="device">
|
||
<span class="font-size-20 font-weight-bold">{{ curentDevice.deviceName }}</span>
|
||
<span
|
||
class="margin-left-10 font-color-fff padding-lr-10 padding-tb-3 border-radius-2"
|
||
:style="{ color: isOnline.color, backgroundColor: '#222e39' }"
|
||
>{{ isOnline.name }}</span
|
||
>
|
||
<span
|
||
class="margin-left-10 font-color-fff padding-lr-10 padding-tb-3 border-radius-2"
|
||
:style="{ color: isShadow.color, backgroundColor: '#222e39' }"
|
||
>{{ isShadow.name }}</span
|
||
>
|
||
</div>
|
||
<!-- 设备选择 -->
|
||
<el-select class="deviceChoose" v-model="curentDeviceId" placeholder="请选择设备" size="mini" @change="getDevice($event)">
|
||
<el-option v-for="item in this.deviceList" :key="item.deviceId" :label="item.deviceName" :value="item.deviceId"> </el-option>
|
||
</el-select>
|
||
</div>
|
||
<div class="margin-top-20">
|
||
<!-- 属性列表 -->
|
||
<div class="propertyList flex" style="overflow: auto">
|
||
<div
|
||
v-for="(item, index) in curentDevice.monitorList"
|
||
:key="index"
|
||
:class="item.id == currentProperty.id ? 'active' : ''"
|
||
@click="handleClickProperty(item)"
|
||
class="propertyItem cursor-pointer width-190 padding-tb-10 padding-lr-20 border-radius-10 flexnone margin-right-10"
|
||
style="background-color: #1f2e3a"
|
||
>
|
||
<!-- 上部分 -->
|
||
<div class="top flex aic">
|
||
<div class="iconBg width-30 height-30 border-radius-25 flex aic jcc" :style="{ backgroundColor: $colorList[index % 7] }">
|
||
<svg-icon class="font-size-20 font-color-fff" :icon-class="item.modelIcon"></svg-icon>
|
||
</div>
|
||
<span class="margin-left-10 font-color-l4">{{ item.name }}</span>
|
||
</div>
|
||
<!-- 下部分 -->
|
||
<div class="bottom flex aib margin-top-10">
|
||
<span class="font-size-20 font-weight-bold">{{ item.value || '--' }}</span>
|
||
<span class="margin-left-10 font-color-l4">{{ item.dataType.unit }}</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<!-- 属性图表 -->
|
||
<div class="propertyChart w100 height-300" ref="propertyChart"></div>
|
||
</div>
|
||
</el-dialog>
|
||
</div>
|
||
</template>
|
||
|
||
<script>
|
||
import { getDevice, listDevice } from '@/api/iot/device';
|
||
import { chartOption } from '@/views/iot/device/components/CommonDeviceView/ChartOption';
|
||
import { getDeviceRunningStatusSingle } from '@/api/iot/device';
|
||
import sysTopics from '@/utils/sysTopics';
|
||
import mqttService from '@/utils/mqttService';
|
||
|
||
export default {
|
||
name: 'Tree',
|
||
dicts: ['iot_device_status'],
|
||
props: {
|
||
baseId: Number,
|
||
},
|
||
data() {
|
||
return {
|
||
currentDate: '',
|
||
currentBase: 'base1',
|
||
//产品列表
|
||
productList: [],
|
||
//弹窗
|
||
deviceDialogVisiable: false,
|
||
//非摄像头设备列表
|
||
deviceList: [],
|
||
//设备弹窗中选中的设备ID,只做监听使用
|
||
curentDeviceId: null,
|
||
//被选中的设备信息
|
||
curentDevice: {
|
||
//初始化值的目的是解决视图渲染的时候报错
|
||
deviceName: '',
|
||
monitorList: [],
|
||
},
|
||
//被选中的属性
|
||
currentProperty: null,
|
||
//图表数据
|
||
propertyChartData: { times: [], values: [] },
|
||
};
|
||
},
|
||
computed: {
|
||
//在线判断
|
||
isOnline() {
|
||
const { status } = this.curentDevice;
|
||
if (status == 3) {
|
||
return { name: '在线', color: '#2b7' };
|
||
}
|
||
if (status == 4) {
|
||
return { name: '离线', color: '#ffffff' };
|
||
} else {
|
||
return { name: '', color: '#ffffff' };
|
||
}
|
||
},
|
||
//影子判断
|
||
isShadow() {
|
||
const { isShadow } = this.curentDevice;
|
||
if (isShadow == 1) {
|
||
return { name: '影子模式', color: '#2b7' };
|
||
} else {
|
||
return { name: '非影子模式', color: '#ffffff' };
|
||
}
|
||
},
|
||
},
|
||
watch: {
|
||
baseId: {
|
||
handler: async function (n) {
|
||
if (n) {
|
||
await this.getProductList();
|
||
await this.getDeviceList();
|
||
// this.$nextTick(() => {
|
||
// this.changePosition();
|
||
// });
|
||
}
|
||
},
|
||
immediate: true,
|
||
},
|
||
propertyChartData: {
|
||
handler: async function () {
|
||
this.loadMap();
|
||
},
|
||
deep: true,
|
||
},
|
||
deviceDialogVisiable(n, o) {
|
||
if (n == false) {
|
||
this.stopAllMonitor();
|
||
}
|
||
},
|
||
},
|
||
created() {
|
||
this.getDate();
|
||
},
|
||
methods: {
|
||
getDate() {
|
||
const date = new Date();
|
||
const year = date.getFullYear();
|
||
const month = String(date.getMonth() + 1).padStart(2, '0');
|
||
const day = String(date.getDate()).padStart(2, '0');
|
||
this.currentDate = `${year}-${month}-${day}`;
|
||
},
|
||
//获取设备所属产品列表
|
||
async getProductList() {
|
||
// 排除掉摄像头
|
||
const { rows } = await listDevice({ baseId: this.baseId, isCamera: 0 });
|
||
// //将设备中包含的产品整理出来
|
||
// let p = rows.map((item) => ({ ...item, imgUrl: item.productImgUrl.split(',')[1] }));
|
||
// this.productList = this._.uniqBy(p, 'productId');
|
||
|
||
const list = [
|
||
{
|
||
id: 'base1',
|
||
productName: '#8010地块',
|
||
imgUrl: require('../img/land-icon.png'),
|
||
url: require('../video/ht1.mp4'),
|
||
videos: [
|
||
require('../video/ht1.mp4'),
|
||
require('../video/ht2.mp4'),
|
||
require('../video/ht3.mp4'),
|
||
require('../video/ht4.mp4'),
|
||
require('../video/ht5.mp4'),
|
||
require('../video/ht6.mp4'),
|
||
],
|
||
type: 'ht',
|
||
list: [
|
||
{
|
||
label: '1号土壤传感器',
|
||
value: '1',
|
||
children: [
|
||
{
|
||
label: '10cm',
|
||
t: '13℃',
|
||
s: '22%',
|
||
ec: '1.2mS/cm',
|
||
ph: 5.5,
|
||
ys: '15,22,150 mg/kg',
|
||
},
|
||
{
|
||
label: '20cm',
|
||
t: '15℃',
|
||
s: '26%',
|
||
ec: '1.3mS/cm',
|
||
ph: 5.5,
|
||
ys: '15,18,145 mg/kg',
|
||
},
|
||
{
|
||
label: '30cm',
|
||
t: '16℃',
|
||
s: '33%',
|
||
ec: '1.7mS/cm',
|
||
ph: 5.5,
|
||
ys: '11,10,100 mg/kg',
|
||
},
|
||
],
|
||
},
|
||
{
|
||
label: '2号土壤传感器',
|
||
value: '2',
|
||
children: [
|
||
{
|
||
label: '10cm',
|
||
t: '10℃',
|
||
s: '28%',
|
||
ec: '0.6mS/cm',
|
||
ph: 6.3,
|
||
ys: '15,22,150 mg/kg',
|
||
},
|
||
{
|
||
label: '20cm',
|
||
t: '11℃',
|
||
s: '22%',
|
||
ec: '0.9mS/cm',
|
||
ph: 6.3,
|
||
ys: '12,18,145 mg/kg',
|
||
},
|
||
{
|
||
label: '30cm',
|
||
t: '9℃',
|
||
s: '15%',
|
||
ec: '1.1mS/cm',
|
||
ph: 6.3,
|
||
ys: '11,10,110 mg/kg',
|
||
},
|
||
],
|
||
},
|
||
],
|
||
},
|
||
{
|
||
id: 'base2',
|
||
productName: '#8023地块',
|
||
imgUrl: require('../img/land-icon.png'),
|
||
url: require('../video/cy1.mp4'),
|
||
videos: [require('../video/cy1.mp4'), require('../video/cy2.mp4'), require('../video/cy3.mp4')],
|
||
type: 'cy',
|
||
list: [
|
||
{
|
||
label: '3号土壤传感器',
|
||
value: '1',
|
||
children: [
|
||
{
|
||
label: '10cm',
|
||
t: '17℃',
|
||
s: '25%',
|
||
ec: '1.0mS/cm',
|
||
ph: 5.9,
|
||
ys: '15,22,139 mg/kg',
|
||
},
|
||
{
|
||
label: '20cm',
|
||
t: '15℃',
|
||
s: '27%',
|
||
ec: '1.2mS/cm',
|
||
ph: 5.9,
|
||
ys: '12,18,126 mg/kg',
|
||
},
|
||
{
|
||
label: '30cm',
|
||
t: '16℃',
|
||
s: '33%',
|
||
ec: '1.3mS/cm',
|
||
ph: 5.9,
|
||
ys: '11,16,111 mg/kg',
|
||
},
|
||
],
|
||
},
|
||
{
|
||
label: '5号土壤传感器',
|
||
value: '2',
|
||
children: [
|
||
{
|
||
label: '10cm',
|
||
t: '13℃',
|
||
s: '18%',
|
||
ec: '0.8mS/cm',
|
||
ph: 6.2,
|
||
ys: '19,28,180 mg/kg',
|
||
},
|
||
{
|
||
label: '20cm',
|
||
t: '12℃',
|
||
s: '22%',
|
||
ec: '0.9mS/cm',
|
||
ph: 6.2,
|
||
ys: '15,25,170 mg/kg',
|
||
},
|
||
{
|
||
label: '30cm',
|
||
t: '9℃',
|
||
s: '15%',
|
||
ec: '1.1mS/cm',
|
||
ph: 6.2,
|
||
ys: '14,20,150 mg/kg',
|
||
},
|
||
],
|
||
},
|
||
],
|
||
},
|
||
];
|
||
this.productList = list;
|
||
this.openDialog(list[0]);
|
||
},
|
||
|
||
//打开弹窗
|
||
async openDialog(product) {
|
||
// this.deviceDialogVisiable = true;
|
||
// //根据产品ID获取产品列表
|
||
// await this.getDeviceList(product.productId);
|
||
// //给第一个设备作为默认选项
|
||
// this.curentDeviceId = this.deviceList[0].deviceId;
|
||
// this.getDevice(this.curentDeviceId);
|
||
this.currentBase = product.id;
|
||
this.$emit('switch', product);
|
||
},
|
||
//获取非摄像头设备列表
|
||
async getDeviceList(productId) {
|
||
const { rows } = await listDevice({ isCamera: 0, productId, baseId: this.baseId });
|
||
this.deviceList = rows;
|
||
},
|
||
|
||
//获取设备详情
|
||
async getDevice(deviceId) {
|
||
const device = await getDevice(deviceId);
|
||
this.curentDevice = device.data;
|
||
const { data } = await getDeviceRunningStatusSingle(deviceId, 0);
|
||
this.$set(this.curentDevice, 'monitorList', data);
|
||
|
||
//给图表查询初始化查询参数
|
||
this.currentProperty = this.curentDevice.monitorList[0];
|
||
//连接mqtt并且订阅主题和回调函数
|
||
// console.log(this.curentDevice.monitorList)
|
||
this.connectMqtt();
|
||
//初始化开始监测
|
||
mqttService.monitor(device.data, 1000);
|
||
},
|
||
//处理属性点击事件
|
||
handleClickProperty(item) {
|
||
//设置一下当前选择的属性
|
||
this.currentProperty = item;
|
||
//图表数据重置
|
||
this.propertyChartData.times = [];
|
||
this.propertyChartData.values = [];
|
||
},
|
||
|
||
//重新初始化图表
|
||
loadMap() {
|
||
chartOption.xAxis.data = this.propertyChartData.times;
|
||
chartOption.series[0].data = this.propertyChartData.values;
|
||
let chart = this.$echarts.init(this.$refs.propertyChart);
|
||
chart.setOption(chartOption);
|
||
},
|
||
//mqtt连接
|
||
async connectMqtt() {
|
||
if (this.$mqttTool.client == null) {
|
||
await this.$mqttTool.connect();
|
||
}
|
||
this.mqttSubscribe();
|
||
this.mqttCallback();
|
||
},
|
||
//mqtt回调
|
||
mqttCallback() {
|
||
this.$mqttTool.client.on('message', (topic, message, buffer) => {
|
||
let _message = JSON.parse(message.toString());
|
||
const { monitorList } = this.curentDevice;
|
||
if (topic.includes(sysTopics.statusFetch)) {
|
||
this.curentDevice.status = _message.status;
|
||
console.log(_message);
|
||
} else {
|
||
//修改monitorList里面的值
|
||
if (monitorList.length > 0) {
|
||
for (let i = 0; i < monitorList.length; i++) {
|
||
for (let j = 0; j < _message.length; j++) {
|
||
if (monitorList[i].id == _message[j].id) {
|
||
monitorList[i].value = _message[j].value / monitorList[i].dataType.step;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
//把值放入propertyChartData
|
||
for (let j = 0; j < _message.length; j++) {
|
||
if (this.currentProperty.id == _message[j].id) {
|
||
this.propertyChartData.times.push(this.parseTime(new Date()));
|
||
this.propertyChartData.values.push(_message[j].value / this.currentProperty.dataType.step);
|
||
}
|
||
}
|
||
}
|
||
});
|
||
},
|
||
mqttPublish(model, deviceDetail) {
|
||
mqttService.mqttPublish(model, deviceDetail);
|
||
},
|
||
//弹窗关闭,批量关闭所有的监测
|
||
stopAllMonitor() {
|
||
this.deviceList.forEach((item, index) => {
|
||
mqttService.monitor(item, 0);
|
||
});
|
||
},
|
||
//mqtt订阅
|
||
mqttSubscribe() {
|
||
// 设备状态主题
|
||
let topicStatus = '/+' + '/+' + sysTopics.statusFetch;
|
||
//设备属性上报主题
|
||
let topicProperty = '/+' + '/+' + sysTopics.propertyFetch;
|
||
//设备功能上报主题
|
||
let topicFunction = '/+' + '/+' + sysTopics.functionFetch;
|
||
//设备监测数据上报主题
|
||
let topicMonitor = '/+' + '/+' + sysTopics.monitorFetch;
|
||
let topics = [];
|
||
topics.push(topicStatus);
|
||
topics.push(topicProperty);
|
||
topics.push(topicFunction);
|
||
topics.push(topicMonitor);
|
||
this.$mqttTool.subscribe(topics);
|
||
},
|
||
|
||
//随机位置
|
||
changePosition() {
|
||
let allDiv = this.$refs.product;
|
||
let that = this;
|
||
function getMaxDimension(divArr) {
|
||
var maxWidth = 0;
|
||
for (var i = 0; i < divArr.length; i++) {
|
||
if (divArr[i].offsetWidth > maxWidth) {
|
||
maxWidth = divArr[i].offsetWidth;
|
||
}
|
||
}
|
||
var maxHeight = 0;
|
||
for (var i = 0; i < divArr.length; i++) {
|
||
if (divArr[i].offsetHeight > maxHeight) {
|
||
maxHeight = divArr[i].offsetHeight;
|
||
}
|
||
}
|
||
var values = { maxWidth: maxWidth, maxHeight: maxHeight };
|
||
return values;
|
||
}
|
||
|
||
function getRDivNumber(min, max) {
|
||
return Math.random() * (max - min) + min;
|
||
}
|
||
|
||
function isCollision(a, b) {
|
||
var a_l = a.offsetLeft; // a_l为a盒子左侧偏移量
|
||
var a_t = a.offsetTop; // a_t为a盒子顶部偏移量
|
||
var a_r = a_l + a.offsetWidth; // a_r为a盒子右侧距页面左侧的距离
|
||
var a_b = a_t + a.offsetHeight; // a_b为a盒子底部距页面最顶端的距离
|
||
var b_l = b.offsetLeft; // b_l等为b盒子 同上解释
|
||
var b_t = b.offsetTop; // b_t为b盒子顶部偏移量
|
||
var b_r = b_l + b.offsetWidth; // b_r为b盒子右侧距页面左侧的距离
|
||
var b_b = b_t + b.offsetHeight; // b_b为b盒子底部距页面最顶端的距离
|
||
|
||
if (b_r < a_l || b_b < a_t || a_r < b_l || a_b < b_t) {
|
||
// 当满足此条件时,没有发生碰撞,此时返回值为false没有检测到碰撞
|
||
return false;
|
||
} else {
|
||
// 否则为true,即发生碰撞
|
||
return true;
|
||
}
|
||
}
|
||
|
||
function computed(divArr) {
|
||
var maxDimensions = getMaxDimension(divArr);
|
||
var widthBoundary = maxDimensions.maxWidth;
|
||
var heightBoundary = maxDimensions.maxHeight;
|
||
for (var i = 0; i < divArr.length; i++) {
|
||
let rDivLeft = getRDivNumber(widthBoundary, that.$refs.tree.offsetWidth - widthBoundary - that.$refs.tree.offsetWidth * 0.2);
|
||
let rDivTop = getRDivNumber(heightBoundary, that.$refs.tree.offsetHeight - heightBoundary - that.$refs.tree.offsetHeight * 0.2);
|
||
divArr[i].style.left = rDivLeft + 'px';
|
||
divArr[i].style.top = rDivTop + 'px';
|
||
}
|
||
examineEach();
|
||
}
|
||
|
||
function examineEach() {
|
||
let maxFrequency = 0;
|
||
maxFrequency += 1;
|
||
for (var i = 0; i < allDiv.length; i++) {
|
||
for (var j = i + 1; j < allDiv.length; j++) {
|
||
if (isCollision(allDiv[i], allDiv[j]) && maxFrequency < 9000) {
|
||
computed([allDiv[i], allDiv[j]]);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
computed(allDiv);
|
||
},
|
||
},
|
||
};
|
||
</script>
|
||
<style lang="scss" scoped>
|
||
.weather-container {
|
||
width: 280px;
|
||
position: absolute;
|
||
right: 0;
|
||
background: rgba(0, 0, 0, 0.5);
|
||
color: white;
|
||
padding: 10px;
|
||
border-radius: 10px;
|
||
}
|
||
|
||
.temperature {
|
||
display: flex;
|
||
flex-direction: row;
|
||
align-items: center;
|
||
margin-bottom: 20px;
|
||
|
||
&-left {
|
||
font-size: 48px;
|
||
margin-right: 50px;
|
||
}
|
||
}
|
||
|
||
.temp-value {
|
||
font-weight: bold;
|
||
}
|
||
|
||
.temp-unit {
|
||
font-size: 24px;
|
||
margin-left: 5px;
|
||
}
|
||
|
||
.weather-info-grid {
|
||
display: grid;
|
||
grid-template-columns: repeat(5, 1fr);
|
||
gap: 10px;
|
||
margin-bottom: 16px;
|
||
}
|
||
|
||
.weather-item {
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
text-align: center;
|
||
}
|
||
|
||
.weather-item .value {
|
||
font-size: 14px;
|
||
font-weight: bold;
|
||
margin-bottom: 5px;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
.weather-item .label {
|
||
font-size: 12px;
|
||
opacity: 0.8;
|
||
}
|
||
|
||
.weather-summary {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
font-size: 14px;
|
||
}
|
||
|
||
.temperature-range {
|
||
opacity: 0.8;
|
||
}
|
||
|
||
//设备树的样式
|
||
.tree {
|
||
width: 100%;
|
||
height: 100%;
|
||
background: url('../img/land-bg.png') no-repeat;
|
||
background-size: 100% auto;
|
||
background-position: center center;
|
||
position: relative;
|
||
|
||
&-date {
|
||
position: absolute;
|
||
left: 20px;
|
||
top: -20px;
|
||
display: flex;
|
||
flex-direction: row;
|
||
background-color: rgba(0, 0, 0, 0.5);
|
||
height: 40px;
|
||
line-height: 40px;
|
||
font-size: 16px;
|
||
color: #fff;
|
||
|
||
span {
|
||
margin: 0 20px;
|
||
}
|
||
|
||
i {
|
||
margin-right: 3px;
|
||
}
|
||
}
|
||
|
||
.product {
|
||
width: 300px;
|
||
height: 300px;
|
||
position: absolute;
|
||
// border-radius: 50%;
|
||
cursor: pointer;
|
||
text-align: center;
|
||
color: #fff;
|
||
font-size: 14px;
|
||
font-weight: 900;
|
||
// background: #fff;
|
||
|
||
&-tips {
|
||
// display: none;
|
||
opacity: 0;
|
||
position: absolute;
|
||
left: 50%;
|
||
transition: all 0.2s ease;
|
||
|
||
// &:hover {
|
||
// .product-info {
|
||
// display: block;
|
||
// }
|
||
// }
|
||
}
|
||
|
||
&.on,
|
||
&:hover {
|
||
.product-tips {
|
||
// display: block;
|
||
opacity: 1;
|
||
transform: scale(1.1);
|
||
}
|
||
}
|
||
|
||
&-1 {
|
||
left: 230px;
|
||
top: 380px;
|
||
|
||
.product-tips {
|
||
top: 12%;
|
||
}
|
||
|
||
.radiating-point {
|
||
position: absolute;
|
||
left: 166px;
|
||
top: 20px;
|
||
}
|
||
}
|
||
|
||
&-2 {
|
||
left: 700px;
|
||
top: 500px;
|
||
|
||
.product-tips {
|
||
top: -6%;
|
||
}
|
||
|
||
.radiating-point {
|
||
position: absolute;
|
||
left: 166px;
|
||
top: -30px;
|
||
}
|
||
}
|
||
|
||
&-info {
|
||
position: absolute;
|
||
left: 80px;
|
||
top: 0px;
|
||
display: inline-block;
|
||
padding: 10px 20px;
|
||
white-space: nowrap;
|
||
background: rgba(255, 255, 255, 0.8);
|
||
border-radius: 10px;
|
||
font-size: 16px;
|
||
color: #333;
|
||
}
|
||
|
||
img {
|
||
height: 70%;
|
||
width: auto;
|
||
}
|
||
}
|
||
}
|
||
|
||
.radiating-point {
|
||
position: relative;
|
||
width: 20px;
|
||
height: 20px;
|
||
margin: 100px auto;
|
||
}
|
||
|
||
.point {
|
||
width: 20px;
|
||
height: 20px;
|
||
background-color: #007bff;
|
||
border-radius: 50%;
|
||
position: absolute;
|
||
top: 0;
|
||
left: 0;
|
||
}
|
||
|
||
.wave {
|
||
position: absolute;
|
||
top: 0;
|
||
left: 0;
|
||
width: 20px;
|
||
height: 20px;
|
||
border: 2px solid #007bff;
|
||
border-radius: 50%;
|
||
opacity: 0;
|
||
animation: radiate 2s infinite;
|
||
}
|
||
|
||
.wave:nth-child(2) {
|
||
animation-delay: 0.5s;
|
||
}
|
||
|
||
.wave:nth-child(3) {
|
||
animation-delay: 1s;
|
||
}
|
||
|
||
@keyframes radiate {
|
||
0% {
|
||
transform: scale(0.1);
|
||
opacity: 1;
|
||
}
|
||
100% {
|
||
transform: scale(3);
|
||
opacity: 0;
|
||
}
|
||
}
|
||
|
||
//弹窗颜色变量,深和浅
|
||
$colorL1: #0c2438;
|
||
$colorL2: #092944;
|
||
$colorL4: #132f41;
|
||
$colorL3: #0d3758;
|
||
//播放弹窗的样式
|
||
.cameraDialog ::v-deep {
|
||
//弹窗头部
|
||
.el-dialog__header {
|
||
background: $colorL1;
|
||
color: #fff;
|
||
}
|
||
//弹窗body
|
||
.el-dialog__body {
|
||
background: $colorL1;
|
||
}
|
||
//播放组建box
|
||
.box {
|
||
height: 100%;
|
||
background: $colorL1;
|
||
}
|
||
.search-menu {
|
||
background: $colorL2;
|
||
color: #fff;
|
||
}
|
||
.el-submenu__title {
|
||
background: $colorL2;
|
||
color: #fff;
|
||
}
|
||
.el-menu {
|
||
background: $colorL2;
|
||
}
|
||
.el-menu-item {
|
||
background: $colorL2;
|
||
color: #fff;
|
||
padding: 0;
|
||
min-width: 0;
|
||
}
|
||
//右侧搜索
|
||
.search-menu-body {
|
||
height: 553px;
|
||
}
|
||
//播放器
|
||
.player {
|
||
height: 650px;
|
||
}
|
||
//容器
|
||
.box {
|
||
border: none;
|
||
}
|
||
//播放器的div容器
|
||
.box-right {
|
||
background: #092944;
|
||
height: 673px !important;
|
||
border: none;
|
||
}
|
||
//分页样式
|
||
.el-pagination .btn-prev {
|
||
background: #092944;
|
||
color: #fff;
|
||
}
|
||
.el-pagination .btn-next {
|
||
background: #092944;
|
||
color: #fff;
|
||
}
|
||
.el-pagination.is-background .el-pager li:not(.disabled).active {
|
||
background: $colorL3;
|
||
color: #fff;
|
||
}
|
||
//搜索按钮
|
||
.el-input__inner {
|
||
background: $colorL3;
|
||
border: none;
|
||
color: #fff;
|
||
}
|
||
}
|
||
//设备兼容弹窗样式
|
||
.deviceDialog {
|
||
.propertyItem.active {
|
||
border: 1px solid green;
|
||
}
|
||
|
||
//穿透的样式
|
||
::v-deep {
|
||
//弹窗头部
|
||
.el-dialog__header {
|
||
background: $colorL1;
|
||
}
|
||
.el-dialog__title {
|
||
color: #fff;
|
||
}
|
||
//弹窗body
|
||
.el-dialog__body {
|
||
background: $colorL1;
|
||
color: #fff;
|
||
}
|
||
|
||
.deviceChoose .el-input input {
|
||
background: $colorL4 !important;
|
||
border: none;
|
||
color: #fff;
|
||
}
|
||
//tabs
|
||
.el-tabs {
|
||
background: $colorL2;
|
||
border: none;
|
||
}
|
||
.el-tabs__header {
|
||
background-color: $colorL3;
|
||
border: none;
|
||
}
|
||
.el-tabs--border-card > .el-tabs__header .el-tabs__item {
|
||
color: #fff !important;
|
||
background-color: $colorL3;
|
||
border: none;
|
||
}
|
||
.el-tabs--border-card > .el-tabs__header .el-tabs__item.is-active {
|
||
color: #fff !important;
|
||
background-color: $colorL2;
|
||
border: none;
|
||
}
|
||
//functionItem
|
||
.functionItem .el-input input {
|
||
background: #585858 !important;
|
||
border: none;
|
||
color: #fff;
|
||
}
|
||
.functionItem .el-input-group__append {
|
||
background-color: #585858 !important;
|
||
border: none;
|
||
border-left: 1px solid #4b4b4b;
|
||
color: #fff;
|
||
}
|
||
}
|
||
}
|
||
</style>
|