zhgdyun/src/views/projectAdmin/dataBoard/AiAnalysisCopy.vue

935 lines
34 KiB
Vue
Raw Normal View History

2022-06-08 14:51:11 +08:00
<template>
<!-- 进度管理 -->
<div class="fullHeight">
<!-- <vue-scroll>
<img src="@/assets/images/dataBoard/6.png" style="height:auto;width:100%"/>
</vue-scroll> -->
<div class="aside fullHeight">
<div class="blockBox">
<div class="blockTitle">
<!-- 预警统计 -->
{{$t('message.dataBoard.alarmStatistics')}}
</div>
<div class="blockContent flex">
<div class="companyChart" ref="echart"></div>
<div class="right-tg">
<ul>
<li v-for="(item,index) in echartData" :key="index">
<span :style="{'background': colorList[index]}"></span>
{{item.name}}
</li>
</ul>
<ul style="margin-left: 20px">
<li v-for="(item,index) in echartData" :key="index">
{{item.value}}
</li>
</ul>
</div>
</div>
</div>
<div class="blockBox">
<div class="blockTitle">
<!-- 设备情况 -->
{{$t('message.dataBoard.devDetail')}}
</div>
<div class="blockContent dev-status">
<vue-scroll>
<ul>
<li v-if="item" class="flex" v-for="(item,index) in devStatusList" :key="index">
{{item.videoName}}
<!-- {{item.name}} -->
<span>{{item.deviceType == 1?'枪机':item.deviceType == 2?'球机':item.deviceType == 3?'热成像':item.deviceType == 4?'单兵':item.deviceType == 5?'全景':'无人机'}}</span>
<!-- <span>{{item.type}}</span> -->
</li>
</ul>
</vue-scroll>
</div>
</div>
<div class="blockBox">
<div class="blockTitle">
<!-- 预警事件 -->
{{$t('message.dataBoard.alarmEvent')}}
</div>
<div style="overflow:hidden;" class="blockContent">
<!-- :data="10" :class-option="defaultOption"-->
<vue-seamless-scroll :data="earlyWarning" :class-option="defaultOption">
<ul class="earlyWarningList">
<li class="earlyWarningList_item" v-for="(item,index) in earlyWarning" :key="index">
<div class="imgBox">
<!-- <img :src="fileUrl + item.imageUrl"/> -->
<!-- <img :src="item.imageUrl"/> -->
<img src="./../../../assets/images/demo.jpg">
</div>
<div class="content">
<!-- <div v-if="item.hardwareName" :title="'设备' + item.hardwareName + '在' + item.location + '检测到' + alarmTypes(item.alarmType) + ',请及时处理...'" class="list-title">{{'设备' + item.hardwareName + '' + item.location + '检测到' + alarmTypes(item.alarmType) + ',请及时处理...'}}</div> -->
<div class="list-title" :title="item.details">{{item.details}}</div>
<!-- <div class="list-time">识别时间{{item.createTime}}</div> -->
<div class="list-title">{{item.time}}</div>
</div>
</li>
</ul>
</vue-seamless-scroll>
</div>
</div>
</div>
<div class="right fullHeight">
<div class="blockBox blockBox3" style="height: calc(66.66% - 25px)">
<div class="blockTitle">
<!-- 抓拍记录 -->
{{$t('message.dataBoard.captureRecords')}}
</div>
<!-- <div @click="scrollClick($event)" style="overflow:hidden;" class="blockContent">-->
<div style="overflow:hidden;" class="blockContent">
<!-- <vue-seamless-scroll :data="captureRecord" :class-option="defaultOption2"> -->
<vue-scroll>
<div class="captureRecordBox">
<div :title="item.time" :data-name="item.id" :data-type="'all'" @click="selectCaptureRecord(item)" v-for="(item,index) in captureRecord" :key="index" class="captureRecord_item">
<div class="imgBox">
<!-- <img :src="fileUrl + item.imageUrl"/> -->
<img :src="item.imageUrl"/>
<!-- <img src="./../../../assets/images/demo.jpg"> -->
</div>
<div class="captureRecord_itemInfo">
<!-- <div :title="item.hardwareName" class="itemInfo itemInfoId">设备名:{{item.hardwareName}}</div>
<div :title="item.createTime" class="itemInfo itemInfoTime">抓拍时间:{{item.createTime}}</div>
<div :title="item.location" class="itemInfo itemInfoPlace">抓拍点:{{item.location}}</div> -->
<div :title="item.name" class="itemInfo itemInfoId"> {{$t('message.dataBoard.devName')+':'}}<!-- 设备名 -->:{{item.name}}</div>
<div :title="item.time" class="itemInfo itemInfoTime">{{$t('message.dataBoard.captureTime')+':'}}<!-- 抓拍时间: -->{{item.time}}</div>
<div :title="item.place" class="itemInfo itemInfoPlace">{{$t('message.dataBoard.captureLocation')+':'}}<!-- 抓拍点: -->{{item.place}}</div>
<!-- 1-安全帽报警2-明火报警3-聚众报警4-倒地报警5-越界报警6-闯入报警7反光衣报警,8-吸烟报警-->
<!-- <div :title="alarmTypes(item.alarmType)" class="itemInfo itemInfoType">抓拍类型:{{alarmTypes(item.alarmType)}}</div> -->
<div :title="alarmTypes(item.type)" class="itemInfo itemInfoType">{{$t('message.dataBoard.captureType')+':'}}<!-- 抓拍类型: -->{{alarmTypes(item.type)}}</div>
</div>
</div>
</div>
</vue-scroll>
<!-- </vue-seamless-scroll> -->
</div>
</div>
<div class="blockBox blockBox2">
<div class="blockTitle">
<!-- 预警趋势 -->
{{$t('message.dataBoard.warningTrend')}}
</div>
<div class="blockContent blockContent2" >
<div class="optionBox">
<div @click="changeOptionBoxListIndex(index)" v-for="(item,index) in optionBoxList" :key="index" class="optionBox_item" :class="{selectOptionBox_item:optionBoxListIndex === index}">
<span>{{item.text}}</span>
<div class="a"></div>
<div class="b"></div>
<div class="c"></div>
<div class="d"></div>
</div>
<!-- <div class="optionBox_item">-->
<!-- 近30天-->
<!-- <div class="a"></div>-->
<!-- <div class="b"></div>-->
<!-- <div class="c"></div>-->
<!-- <div class="d"></div>-->
<!-- </div>-->
</div>
<div ref="echart2" style="width: 100%;height: 100%" class="stageBox">
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import echarts from 'echarts4';;
import mqtt from "mqtt";
import vueSeamlessScroll from 'vue-seamless-scroll'
import {
getAiAnalyseHardWareAlarmTotalApi,//查询所有各预警类型预警数 (预警统计)
selectAiAnalyseHardWareAlarmTrendListApi,//查询近七天或近30天报警趋势(预计趋势)
selectAIVideoTypeCountListApi,//按照摄像头类型查询具有AI功能的摄像头数量(设备情况)
selectAiAnalyseHardWareAlarmListApi//查询设备报警记录列表(预警记录&&抓拍记录)
} from "@/assets/js/api/AI";
const options = {
connectTimeout: 40000,
clientId:
"mqttjs_" +
Math.random()
.toString(16)
.substr(2, 8),
username: "root",
password: "123456",
clean: true
};
let client = null;
export default {
data() {
return {
optionBoxList:[
{
text:/* "近7天" */this.$t('message.dataBoard.timeList')[0]
},
{
text:/* "近30天" */this.$t('message.dataBoard.timeList')[1]
}
],
optionBoxListIndex:0,
colorList: ['#44D7B6','#3052B3', '#FE6C7F', '#FAC915','#91c7ae','#749f83','#ca8622','#bda29a'],
chart1: Object,
chart2: Object,
option1:{},
option1:{},
// [
// {
// details:"摄像机一号在钢筋加工棚监测到有未戴安全帽,请及时处理…",
// time:"09-12 13:45:42"
// },
// {
// details:"摄像机一号在钢筋加工棚监测到有未戴安全帽,请及时处理…",
// time:"09-12 13:45:42"
// },
// ],
earlyWarning:this.$t('message.dataBoard.earlyWarning'),
// [
// {value: 0, name: '车辆冲洗'},
// {value: 0, name: '运输车辆密闭运输'},
// {value: 0, name: '裸土覆盖'},
// {value: 0, name: '围挡上报记录'},
// {value: 0, name: '路面硬化上报记录'},
// {value: 0, name: '湿法作业上报记录'},
// ],
echartData: this.$t('message.dataBoard.echartData'),
totalNum:0,
// [
// {
// name: '设备一号',
// type: '枪机'
// },{
// name: '设备二号',
// type: '球机'
// },{
// name: '设备三号',
// type: '无人机'
// }],
devStatusList:this.$t('message.dataBoard.devStatusList2'),
// [
// {
// name: '无人机',
// id:'900',
// time: '09-11 15:00:00',
// place:'施工通道',
// type:1,
// imageUrl: 'http://124.71.178.44:30/image/71b019f8-09ea-42d7-b7cd-842ec34e330b.jpg'
// },
// {
// name: '无人机',
// id:'901',
// time: '09-11 15:00:00',
// place:'施工通道',
// type: 1,
// imageUrl: 'http://124.71.178.44:30/image/14e45426-6d94-4a97-a91e-74c1c9976b56.jpg'
// }
// ],
captureRecord:this.$t('message.dataBoard.captureRecordList'),
userId: "",
topicName: "aiAnalyse",
dataTimeList:[],
alarmTypeNum1:[],
alarmTypeNum2:[],
alarmTypeNum3:[],
alarmTypeNum4:[],
alarmTypeNum5:[],
alarmTypeNum6:[],
alarmTypeNum7:[],
alarmTypeNum8:[],
alarmTotalNum:[],
fileUrl:"",
currentPersonDetail:''
};
},
created(){
this.fileUrl = this.$store.state.FILEURL;
console.log(this.$store.state.userInfo.scope);
this.getAiAnalyseHardWareAlarmTotal()
this.selectAiAnalyseHardWareAlarmTrendList(this.optionBoxListIndex+1)
this.selectAIVideoTypeCountList()
// this.selectAiAnalyseHardWareAlarmList()
},
mounted() {
// client = mqtt.connect("ws://139.159.226.224:8083/mqtt", options);
client = mqtt.connect(mqttUrl, options);
this.mqttMSG();
},
beforeDestroy() {
if(client){
client.unsubscribe(this.topicName + this.$store.state.projectSn);
}
},
components: {
vueSeamlessScroll
},
computed: {
alarmTypes(){
return function (type) {
let alarmType
if(type == 1){
alarmType = /* '车辆冲洗' */this.$t('message.dataBoard.echartData')[0]
}else if (type == 2){
alarmType = /* '运输车辆密闭运输' */this.$t('message.dataBoard.echartData')[1]
} else if (type == 3){
alarmType = /* '裸土覆盖' */this.$t('message.dataBoard.echartData')[2]
}else if (type == 4){
alarmType = /* '围挡上报记录' */this.$t('message.dataBoard.echartData')[3]
}else if (type == 5){
alarmType = /* '路面硬化上报记录' */this.$t('message.dataBoard.echartData')[4]
}else if (type == 6){
alarmType = /* '湿法作业上报记录' */this.$t('message.dataBoard.echartData')[5]
}
return alarmType
}
},
defaultOption () {
return {
step: 0.5, // 数值越大速度滚动越快
limitMoveNum: 3, // 开始无缝滚动的数据量 this.dataList.length
hoverStop: true, // 是否开启鼠标悬停stop
direction: 1, // 0向下 1向上 2向左 3向右
openWatch: true, // 开启数据实时监控刷新dom
singleHeight: 0, // 单步运动停止的高度(默认值0是无缝不停止的滚动) direction => 0/1
singleWidth: 0, // 单步运动停止的宽度(默认值0是无缝不停止的滚动) direction => 2/3
waitTime: 1000, // 单步运动停止的时间(默认值1000ms)
}
},
defaultOption2 () {
return {
step: 0.5, // 数值越大速度滚动越快
limitMoveNum: 8, // 开始无缝滚动的数据量 this.dataList.length
hoverStop: true, // 是否开启鼠标悬停stop
direction: 1, // 0向下 1向上 2向左 3向右
openWatch: true, // 开启数据实时监控刷新dom
singleHeight: 0, // 单步运动停止的高度(默认值0是无缝不停止的滚动) direction => 0/1
singleWidth: 0, // 单步运动停止的宽度(默认值0是无缝不停止的滚动) direction => 2/3
waitTime: 1000, // 单步运动停止的时间(默认值1000ms)
}
},
},
methods: {
//查询所有各预警类型预警数 (预警统计)
getAiAnalyseHardWareAlarmTotal(){
getAiAnalyseHardWareAlarmTotalApi({
projectSn:this.$store.state.projectSn,
}).then((res) => {
this.echartData[0].value = res.result.alarmTypeNum1
this.echartData[1].value = res.result.alarmTypeNum2
this.echartData[2].value = res.result.alarmTypeNum3
this.echartData[3].value = res.result.alarmTypeNum4
this.echartData[4].value = res.result.alarmTypeNum5
this.echartData[5].value = res.result.alarmTypeNum6
this.totalNum = res.result.totalNum
this.createdEchart1()
console.log(this.echartData);
});
},
changeOptionBoxListIndex(index){
this.optionBoxListIndex = index
this.selectAiAnalyseHardWareAlarmTrendList(index+1)
},
//查询近七天或近30天报警趋势(预计趋势)
selectAiAnalyseHardWareAlarmTrendList(selectType){
selectAiAnalyseHardWareAlarmTrendListApi({
projectSn:this.$store.state.projectSn,
selectType:selectType
}).then((res) => {
this.alarmTypeNum1 = []
this.alarmTypeNum2 = []
this.alarmTypeNum3 = []
this.alarmTypeNum4 = []
this.alarmTypeNum5 = []
this.alarmTypeNum6 = []
this.alarmTypeNum7 = []
this.alarmTypeNum8 = []
this.alarmTotalNum = []
this.dataTimeList = []
res.result.forEach((item) => {
this.alarmTypeNum1.push(item.alarmTypeNum1)
this.alarmTypeNum2.push(item.alarmTypeNum2)
this.alarmTypeNum3.push(item.alarmTypeNum3)
this.alarmTypeNum4.push(item.alarmTypeNum4)
this.alarmTypeNum5.push(item.alarmTypeNum5)
this.alarmTypeNum6.push(item.alarmTypeNum6)
this.alarmTypeNum7.push(item.alarmTypeNum7)
this.alarmTypeNum8.push(item.alarmTypeNum8)
this.alarmTotalNum.push(item.totalNum)
this.dataTimeList.push(item.dayTitle)
this.createdEchart2()
// console.log(item);
})
console.log(res);
});
},
//按照摄像头类型查询具有AI功能的摄像头数量(设备情况)
selectAIVideoTypeCountList(){
selectAIVideoTypeCountListApi({
projectSn:this.$store.state.projectSn
}).then((res) => {
// 1 枪机2球机3热成像4单兵5全景6无人机
this.devStatusList = res.result
console.log(res);
});
},
//查询设备报警记录列表(预警记录&&抓拍记录)
selectAiAnalyseHardWareAlarmList(){
selectAiAnalyseHardWareAlarmListApi({
projectSn:this.$store.state.projectSn,
sizeNum:20
}).then((res) => {
this.earlyWarning = res.result
this.captureRecord = res.result
console.log(res);
});
},
// scrollClick(e) {
// //通过 e.target获取点击的dom
// //通过e.target.dataset获取vuedom中的自定义属性
// let data = e.target.dataset;
// this.$emit("supervise-detail", data.name, data.type);
// console.log(data);
// },
createdEchart1(){
// console.log(this.$refs['echart'])
let chart1 = echarts.init(this.$refs['echart']);
this.chart1 = chart1;
chart1.clear();
this.option1 = {
grid:{
top:"0px",
left:"0px",
right:"0px",
bottom:"0px"
},
tooltip: {
trigger: 'item'
},
legend: {
show: false,
},
graphic:[{
type: 'text',
left: 'center',
top: '38%',
style:{
text: this.totalNum,
textAlign: 'center',
fill: '#fff',
fontSize: 26
}
},{
type: 'text',
left: 'center',
top: '55%',
style:{
text: /* '问题总数', */this.$t('message.dataBoard.questionAllCounts'),
textAlign: 'center',
fill: '#fff',
fontSize: 14
}
}],
color:this.colorList,
series: [
{
type: 'pie',
radius: ['55%', '70%'],
center:['50%','50%'],
avoidLabelOverlap: false,
label: {
show: false,
position: 'center'
},
emphasis: {
label: {
show: false,
fontSize: '16',
color: "#fff"
}
},
labelLine: {
show: false
},
data: this.echartData,
stillShowZeroSum: true,
minShowLabelAngle: 10
},
]
}
chart1.setOption(this.option1);
},
createdEchart2(){
// console.log(this.$refs['echart'])
let chart2 = echarts.init(this.$refs['echart2']);
this.chart2 = chart2;
chart2.clear();
this.option2 = {
color:['#557DED','#44D7B6','#3052B3', '#FE6C7F', '#FAC915','#91c7ae','#749f83','#ca8622','#bda29a'],
legend: {
// ['总计', '车辆冲洗','运输车辆密闭运输','裸土覆盖','围挡上报记录','路面硬化上报记录','湿法作业上报记录']
data:this.$t('message.dataBoard.echartNameData'),
textStyle:{
// fontSize: 14,//字体大小
color: '#FEFFFF'//字体颜色
},
left:"10%",
top:"6%"
},
tooltip:{
trigger: 'axis',
position: [20, 20]
},
xAxis: {
type: 'category',
data: this.dataTimeList,
axisLabel : {
formatter: '{value}',
textStyle: { //改变刻度字体样式
color: 'RGB(254,255,255,0.5)'
}
}
},
yAxis: {
type: 'value',
axisLabel : {
formatter: '{value}',
textStyle: { //改变刻度字体样式
color: 'RGB(254,255,255,0.5)'
}
},
splitLine: {
show: true,
lineStyle:{
type:'dashed',
color:"RGB(236,236,236,0.5)"
}
}
},
series: [
{
name:/* "总计", */this.$t('message.dataBoard.echartNameData')[0],
data: this.alarmTotalNum,
type: 'line',
smooth: true,
itemStyle : {
normal : {
lineStyle:{
color:'#557DED'
}
}
},
},
{
name:/* "车辆冲洗", */this.$t('message.dataBoard.echartNameData')[1],
data: this.alarmTypeNum1,
type: 'line',
smooth: true,
itemStyle : {
normal : {
lineStyle:{
color:'#44D7B6'
}
}
},
},
{
name:/* "运输车辆密闭运输", */this.$t('message.dataBoard.echartNameData')[2],
data: this.alarmTypeNum2,
type: 'line',
smooth: true,
itemStyle : {
normal : {
lineStyle:{
color:'#3052B3'
}
}
},
},
{
name:/* "裸土覆盖", */this.$t('message.dataBoard.echartNameData')[3],
data: this.alarmTypeNum3,
type: 'line',
smooth: true,
itemStyle : {
normal : {
lineStyle:{
color:'#FE6C7F'
}
}
},
},
{
name:/* "围挡上报记录", */this.$t('message.dataBoard.echartNameData')[4],
data: this.alarmTypeNum4,
type: 'line',
smooth: true,
itemStyle : {
normal : {
lineStyle:{
color:'#FAC915'
}
}
},
},
{
name:/* "路面硬化上报记录", */this.$t('message.dataBoard.echartNameData')[5],
data: this.alarmTypeNum5,
type: 'line',
smooth: true,
itemStyle : {
normal : {
lineStyle:{
color:'#91c7ae'
}
}
},
},
{
name:/* "湿法作业上报记录", */this.$t('message.dataBoard.echartNameData')[6],
data: this.alarmTypeNum6,
type: 'line',
smooth: true,
itemStyle : {
normal : {
lineStyle:{
color:'#749f83'
}
}
},
}
]
}
chart2.setOption(this.option2);
},
mqttMSG() {
// mqtt连接 +"/#" +workerId
client.on("connect", (e) => {
console.log("连接成功:", this.topicName + this.$store.state.projectSn);
client.subscribe(this.topicName + this.$store.state.projectSn, { qos: 0 }, (error) => {
if (!error) {
console.log("订阅成功");
} else {
console.log("订阅失败");
}
});
});
// 接收消息处理
client.on("message", (topic, message) => {
console.log(message);
message = JSON.parse(message);
this.currentPersonDetail=JSON.parse(message.content)
console.log(this.currentPersonDetail);
if (this.currentPersonDetail){
if(this.earlyWarning.length < 20){
let arr = [this.currentPersonDetail]
this.earlyWarning = arr.concat(this.earlyWarning)
this.captureRecord = arr.concat(this.captureRecord)
}else {
this.earlyWarning.pop()
this.captureRecord.pop()
this.earlyWarning.unshift(this.currentPersonDetail)
this.captureRecord.unshift(this.currentPersonDetail)
}
}
// if(message.content){
// if(message.content.indexOf("火点检测") > -1 || message.content.indexOf("温度报警") > -1){
// this.$emit('sendMsg')
// }
// }
// this.$notify({
// title: message.title,
// message: message.content,
// });
});
// 断开发起重连
// client.on("reconnect", (error) => {
// console.log("正在重连:", error);
// });
// 链接异常处理
client.on("error", (error) => {
console.log("连接失败:", error);
});
},
selectCaptureRecord(e){
console.log(e);
}
},
};
</script>
<style lang="less" scoped>
/deep/ .stageBox{
div{
canvas{
/*left: -70px !important;*/
top: -25px !important;
/*width: 1500px !important;*/
height: 300px !important;
}
}
}
.a {
width: 5px;
height: 5px;
position: absolute;
top: 0;
left: 0;
border-left: 2px solid #EBEBEB;
border-top: 2px solid #EBEBEB;
}
.b {
width: 5px;
height: 5px;
position: absolute;
top: 0;
right: 0;
border-right: 2px solid #EBEBEB;
border-top: 2px solid #EBEBEB;
}
.c {
width: 5px;
height: 5px;
position: absolute;
bottom: 0;
left: 0;
border-bottom: 2px solid #EBEBEB;
border-left: 2px solid #EBEBEB;
}
.d {
width: 5px;
height: 10px;
position: absolute;
bottom: 0;
right: 0;
border-right: 2px solid #EBEBEB;
border-bottom: 2px solid #EBEBEB;
}
.optionBox{
position: absolute;
right: 50px;
top: 0px;
.optionBox_item{
cursor:pointer;
z-index: 100;
padding: 4px;
display: inline-block;
width: 52px;
height: 22px;
font-size: 12px;
line-height: 26px;
margin-right: 10px;
text-align: center;
background: #193B43;
position: relative;
}
.selectOptionBox_item{
background: #393204;
color: #F7D300;
}
}
.earlyWarningList{
.earlyWarningList_item{
padding: 15px ;
height: 95px;
background: #0D192C;
margin-bottom: 5px;
box-sizing: border-box;
.imgBox{
display: inline-block;
box-sizing: border-box;
img{
width: 79px;
height: 67px;
}
}
.content{
height: 100%;
box-sizing: border-box;
margin-left: 17px;
width: 243px;
display: inline-block;
padding-bottom: 13px;
.list-title{
margin-bottom: 13px;
font-size: 15px;
text-overflow: ellipsis;
line-clamp: 2;
overflow: hidden;
color: #C83E50;
}
.list-time{
font-size: 13px;
}
}
}
}
.captureRecordBox{
/*display: flex;*/
.captureRecord_item{
box-sizing: border-box;
display: inline-block;
width: 305px;
height: 247px;
margin-right: 25px;
margin-bottom: 25px;
.captureRecord_itemInfo{
.itemInfo{
font-size: 12px;
display: inline-block;
width: 152px;
overflow: hidden;
text-overflow:ellipsis; white-space: nowrap;
}
.itemInfoId{
}
.itemInfoTime{
}
.itemInfoPlace{
}
.itemInfoType{
}
}
}
.imgBox{
width: 100%;
img{
width: 100%;
height: 190px;
}
}
}
.numContent {
display: flex;
align-items: center;
justify-content: space-around;
p{
font-size: 14px;
opacity: 0.88;
margin-top: 10px;
text-align: center;
}
}
.companyChart{
width: 50%;
height: 100%;
}
/deep/.alarmTypeBox{
position: absolute;
top: 20px;
right: 10px;
width: 66px;
opacity: 0.8;
z-index: 3;
.el-input__inner{
background-color: transparent;
color: white;
height: 24px;
line-height: 24px;
padding: 0 5px;
}
.el-input__suffix{
right: 0px;
}
.el-input__icon{
color: white;
line-height: 24px;
}
}
.right-tg{
// margin-left: 20px;
display: flex;
ul{
display: flex;
height: 100%;
flex-direction: column;
//align-items: center;
justify-content: center;
li{
margin-bottom: 10px;
display: flex;
align-items: center;
span{
width: 6px;
height: 6px;
display: block;
border-radius: 50%;
margin-right: 6px;
}
}
}
}
.configBtn{
position: absolute;
right: 8px;
top: 15px;
font-size: 20px;
cursor: pointer;
z-index: 3;
}
.days{
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%,-50%);
.num{
font-size: 46px;
}
}
.daysBG{
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%,-50%);
}
.endDate{
position: absolute;
right: 15px;
bottom: 12px;
// font-size: 13px;
}
.Extgantt{
width: 100%;
height: 100% ;
border: none;
}
.flex{
display: flex;
}
.dev-status{
ul{
li{
background: rgba(#2F4988, 0.3);
color: #fff;
justify-content: space-between;
padding-left: 32px;
height: 37px;
line-height: 37px;
margin-bottom: 6px;
span{
display: block;
width: 65px;
text-align: center;
background: rgba(#557DED,0.6);
color: #fff;
}
}
}
}
</style>