From 761dc97c8ac017e5d57b331f7bcf3cfaf1ca1159 Mon Sep 17 00:00:00 2001 From: quanyawei <401863037@qq.com> Date: Fri, 08 Nov 2024 15:44:06 +0800 Subject: [PATCH] fix: 无人机轨迹修改 --- src/views/UVA/index.vue | 519 ++++++++++++++++++++++++++++++++++++++------------------ 1 files changed, 349 insertions(+), 170 deletions(-) diff --git a/src/views/UVA/index.vue b/src/views/UVA/index.vue index 382c68c..7b12939 100644 --- a/src/views/UVA/index.vue +++ b/src/views/UVA/index.vue @@ -7,45 +7,24 @@ > <div style="width: 274px; margin: 13px auto"> <el-date-picker + ref="datePick" + v-model="datenum" :picker-options="pickerOptions" placeholder="������������" popper-class="jlpMySelectPopper" - ref="datePick" - v-model="datenum" + value-format="yyyy-MM-dd" + style="width: 280px" @change="chooseDate" @blur="chooseDate1" @focus="chooseDate2" - value-format="yyyy-MM-dd" - style="width: 280px" - > - </el-date-picker> + /> </div> - <!-- <el-card class="box-card" style="width: 274px; margin: 13px auto"> --> - - <!-- <div v-else style="height: 180px; width: 274px; overflow-x: hidden"> - <div - style=" - width: 272px; - text-align: center; - height: 180px; - line-height: 140px; - font-size: 14px; - color: #5a5c60; - " - > - ��������������� - </div> - </div> --> - <!-- </el-card> --> - <div style="width: 274px; margin: 10px auto; border-radius: 8px" class="coll" > <!--accordion ���������������--> <el-collapse - accordion - style="box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1)" v-show="shou1 === true" v-loading="loading" > @@ -56,23 +35,22 @@ <img style="position: absolute; left: 18px" src="../../assets/images/uav/uav.png" - /> + > <span style="display: inline-block; position: absolute; left: 20px" > - ������������������������������</span - > + ������������������������������</span> </template> </el-collapse-item> </el-collapse> <el-collapse + v-show="shou1 === false" + ref="collapse" v-model="asideData.activeNames" + v-loading="loading" accordion style="box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1)" @change="handleChange" - ref="collapse" - v-show="shou1 === false" - v-loading="loading" > <el-collapse-item v-for="(item1, index) in asideData.uavTimeFly" @@ -84,12 +62,11 @@ <img style="position: absolute; left: 18px" src="../../assets/images/uav/uav.png" - /> + > <span style="display: inline-block; position: absolute; left: 20px" > - {{ item1.name }}</span - > + {{ item1.name }}</span> </template> <el-scrollbar style="height: 200px; overflow-x: hidden"> <div @@ -130,34 +107,37 @@ > <div class="numss"> <el-radio-group + v-if="selecttrue === 1" v-model="radioSeven" size="medium" - @change="changeCode" - v-if="selecttrue === 1" style="margin-top: 10px; margin-left: 10px" + @change="changeCode" > - <el-radio-button label="PM2.5"></el-radio-button> - <el-radio-button label="PM10"></el-radio-button> - <el-radio-button label="SO2"></el-radio-button> - <el-radio-button label="NO2"></el-radio-button> - <el-radio-button label="CO"></el-radio-button> - <el-radio-button label="03"></el-radio-button> - <el-radio-button label="TVOC"></el-radio-button> + <el-radio-button label="PM2.5" /> + <el-radio-button label="PM10" /> + <el-radio-button label="SO2" /> + <el-radio-button label="NO2" /> + <el-radio-button label="CO" /> + <el-radio-button label="03" /> + <el-radio-button label="TVOC" /> </el-radio-group> - <div class="Duo" v-if="selecttrue === 2"> + <div + v-if="selecttrue === 2" + class="Duo" + > <div class="spantuu"> <span>���������������������������(���): </span> <el-input - class="inputtu" - v-model="tallone" ref="uvas" - ></el-input> + v-model="tallone" + class="inputtu" + /> -- <el-input - class="inputtu" - v-model="talltwo" ref="uvas" - ></el-input> + v-model="talltwo" + class="inputtu" + /> </div> <!-- <el-select v-model="Duovalue" placeholder="������������" class="slee"> <el-option @@ -169,23 +149,25 @@ </el-option> </el-select> --> <div class="spantu"> - <span>������������(���): </span - ><el-input - class="inputtu" + <span>������������(���): </span><el-input + ref="uvas" v-model="uvasize" + class="inputtu" clearable placeholder="���������������" - ref="uvas" - ></el-input> + /> </div> - <el-select v-model="Duovalue" placeholder="������������" class="slee"> + <el-select + v-model="Duovalue" + placeholder="������������" + class="slee" + > <el-option v-for="item in optionsduo" :key="item.code" :label="item.name" :value="item.name" - > - </el-option> + /> </el-select> <!-- <div class="spantuu"> <span>���������������������������(���): </span> @@ -202,10 +184,17 @@ ></el-input> </div> --> </div> - <div v-if="selecttrue === 1" style="margin-left: 10px"> - <el-button type="primary" @click="gengD" style="margin-top: 10px" - >������������</el-button + <div + v-if="selecttrue === 1" + style="margin-left: 10px" + > + <el-button + type="primary" + style="margin-top: 10px" + @click="gengD" > + ������������ + </el-button> </div> <div v-if="selecttrue === 2" @@ -216,10 +205,21 @@ type="primary" icon="el-icon-setting" @click="dialogFormVisible = true" - >6���������</el-button > - <el-button class="gengD" @click="shou">������</el-button> - <el-button type="primary" @click="selectDuo">������</el-button> + 6��������� + </el-button> + <el-button + class="gengD" + @click="shou" + > + ������ + </el-button> + <el-button + type="primary" + @click="selectDuo" + > + ������ + </el-button> </div> </div> <!-- <div class="Duo" v-if="selecttrue === 2"> @@ -251,22 +251,67 @@ </div> --> </div> <!-- <div v-if="noneData" class="noneData">������������������������������</div> --> - <div id="map_container" v-loading="loading1" /> + <div + id="map_container" + v-loading="loading1" + /> + <div class="dataParameter"> + <dir class="item"> + <div + v-for="(item, index) in temMergeDataList" + v-show="index < 3" + :key="index" + > + <p> {{ item.name }}:{{ item.value }}</p> + </div> + </dir> + <div + class="item1" + style="margin-left: 10px;" + > + <div + v-for="(item, index) in temMergeDataList" + v-show="index > 2" + :key="index" + > + <p> {{ item.name }}:{{ item.value }}</p> + </div> + </div> + </div> </el-main> </el-container> - <el-dialog title="6���������" :visible.sync="dialogFormVisible" width="1000px"> - <el-descriptions title="������6���" :column="3" border> + <el-dialog + title="6���������" + :visible.sync="dialogFormVisible" + width="1000px" + > + <el-descriptions + title="������6���" + :column="3" + border + > <el-descriptions-item label="PM2.5 | ug/m��" label-class-name="my-label" content-class-name="my-content" - >22</el-descriptions-item > - <el-descriptions-item label="PM10 | ug/m��">34</el-descriptions-item> - <el-descriptions-item label="SO2 | ug/m��">4</el-descriptions-item> - <el-descriptions-item label="NO2 | ug/m��">16</el-descriptions-item> - <el-descriptions-item label="CO | mg/m��">0.5</el-descriptions-item> - <el-descriptions-item label="O3 | ug/m��">149</el-descriptions-item> + 22 + </el-descriptions-item> + <el-descriptions-item label="PM10 | ug/m��"> + 34 + </el-descriptions-item> + <el-descriptions-item label="SO2 | ug/m��"> + 4 + </el-descriptions-item> + <el-descriptions-item label="NO2 | ug/m��"> + 16 + </el-descriptions-item> + <el-descriptions-item label="CO | mg/m��"> + 0.5 + </el-descriptions-item> + <el-descriptions-item label="O3 | ug/m��"> + 149 + </el-descriptions-item> </el-descriptions> <!-- <el-descriptions title="���������������" border> </el-descriptions> --> @@ -282,44 +327,81 @@ > ��������������� </div> - <el-table :data="sensorTableData" border> - <el-table-column prop="sensorName" label="������" /> - <el-table-column prop="unit" label="������" /> + <el-table + :data="sensorTableData" + border + > + <el-table-column + prop="sensorName" + label="������" + /> + <el-table-column + prop="unit" + label="������" + /> <el-table-column label="������"> <template slot-scope="scope"> - <el-input v-model="scope.row.tab1" placeholder="���������������" /> + <el-input + v-model="scope.row.tab1" + placeholder="���������������" + /> <!-- <span v-show="!scope.row.show">{{ scope.row.tab1 }}</span> --> </template> </el-table-column> <el-table-column label="������"> <template slot-scope="scope"> - <el-input v-model="scope.row.tab2" placeholder="���������������" /> + <el-input + v-model="scope.row.tab2" + placeholder="���������������" + /> </template> </el-table-column> <el-table-column label="������"> <template slot-scope="scope"> - <el-input v-model="scope.row.tab3" placeholder="���������������" /> + <el-input + v-model="scope.row.tab3" + placeholder="���������������" + /> </template> </el-table-column> <el-table-column label="������"> <template slot-scope="scope"> - <el-input v-model="scope.row.tab4" placeholder="���������������" /> + <el-input + v-model="scope.row.tab4" + placeholder="���������������" + /> </template> </el-table-column> <el-table-column label="������"> <template slot-scope="scope"> - <el-input v-model="scope.row.tab5" placeholder="���������������" /> + <el-input + v-model="scope.row.tab5" + placeholder="���������������" + /> </template> </el-table-column> <el-table-column label="������"> <template slot-scope="scope"> - <el-input v-model="scope.row.tab6" placeholder="���������������" /> + <el-input + v-model="scope.row.tab6" + placeholder="���������������" + /> </template> </el-table-column> </el-table> - <div slot="footer" class="dialog-footer"> - <el-button @click="dialogFormVisible = false">��� ���</el-button> - <el-button type="primary" @click="customLevel">��� ���</el-button> + <div + slot="footer" + class="dialog-footer" + > + <el-button @click="dialogFormVisible = false"> + ��� ��� + </el-button> + <el-button + type="primary" + @click="customLevel" + > + ��� ��� + </el-button> </div> </el-dialog> </div> @@ -389,12 +471,20 @@ break } - if (dLat > 0) pLat = wgsLat - else mLat = wgsLat - if (dLon > 0) pLon = wgsLon - else mLon = wgsLon + if (dLat > 0) { + pLat = wgsLat + } else { + mLat = wgsLat + } + if (dLon > 0) { + pLon = wgsLon + } else { + mLon = wgsLon + } - if (++i > 10000) break + if (++i > 10000) { + break + } } return { lat: wgsLat, lon: wgsLon } }, @@ -448,8 +538,12 @@ var y = Math.sin((latA * this.PI) / 180.0) * Math.sin((latB * this.PI) / 180.0) var s = x + y - if (s > 1) s = 1 - if (s < -1) s = -1 + if (s > 1) { + s = 1 + } + if (s < -1) { + s = -1 + } var alpha = Math.acos(s) var distance = alpha * earthR return distance @@ -515,11 +609,13 @@ export default { filters: { sensorFilter: function (value) { - if (!value) return '' + if (!value) { + return '' + } return json[value] }, }, - data() { + data () { return { dialogFormVisible: false, chosee: 1, @@ -532,7 +628,7 @@ selecttrue: 1, pickerOptions: { cellClassName: (time) => { - let timeDate = moment(time.getTime()).format('yyyy-MM-DD') + const timeDate = moment(time.getTime()).format('yyyy-MM-DD') if (this.timeNums.includes(timeDate)) { return 'dateArrClass' // ������������������������������������������ } @@ -601,7 +697,9 @@ // ������������ ������������ this.timeOne = minDate.getTime() // ��������������������� ������������������ // ������������������������������������������������������������ - if (maxDate) this.timeOne = '' + if (maxDate) { + this.timeOne = '' + } }, disabledDate: (time) => { if (this.timeOne) { @@ -865,17 +963,11 @@ tab6: '50000', }, ], + temMergeDataList: [] } }, - - mounted() { - this.initStart() - // this.$refs.datePick.focus() - // this.getDate() - // this.flyData() - }, watch: { - dataTypeValue(n, o) { + dataTypeValue (n, o) { if (this.dataTypeValue === 'webSocket') { this.dateValue = [] this.historyView = false @@ -886,18 +978,28 @@ this.webSocketView = false } }, - dateValue(n, o) { + dateValue (n, o) { if (n === null) { this.dateValue = [] } }, - viewKey(n, o) { + viewKey (n, o) { // console.log(n) }, deep: true, immediate: true, }, - created() { + + mounted () { + this.$nextTick(() => { + this.initStart() + }) + + // this.$refs.datePick.focus() + // this.getDate() + // this.flyData() + }, + created () { this.newTime(this.timeValue) this.newDate() this.getDate() @@ -905,11 +1007,11 @@ // this.getFlyData() }, methods: { - customLevel() { + customLevel () { this.selectDuo() this.dialogFormVisible = false }, - selectDuo() { + selectDuo () { // console.log(2115); if (this.chosee === 1) { this.$message.warning('������������������������������������') @@ -955,21 +1057,21 @@ this.initStart(this.carData) }) }, - chooseDate() { + chooseDate () { // this.$refs.datePick.focus() // ��������������������������������� this.getTimeAreaData(this.datenum) $('.coll').css('margin-top', '350px') }, - chooseDate2() { + chooseDate2 () { // this.$refs.datePick.focus() // ��������������������������������� // this.getTimeAreaData(this.datenum) $('.coll').css('margin-top', '350px') }, - chooseDate1() { + chooseDate1 () { $('.coll').css('margin-top', '10px') // this.$refs.datePick.focus() // ��������������������������������� }, - gengD() { + gengD () { // if (this.zhanK === 1) { // this.$message.warning('���������������������������������������') // return @@ -977,11 +1079,11 @@ this.selecttrue = 2 $('.numss').css({ width: '1050px' }) }, - shou() { + shou () { this.selecttrue = 1 $('.numss').css({ width: '700px' }) }, - parseTime(time, cFormat) { + parseTime (time, cFormat) { if (arguments.length === 0 || !time) { return null } @@ -1021,7 +1123,7 @@ }) return time_str }, - newTime2(timeArr) { + newTime2 (timeArr) { var arr = [] timeArr.map((v) => { var date = new Date(v) @@ -1041,11 +1143,11 @@ return arr }, // ��������������������������������������� - Rad(d) { + Rad (d) { return (d * Math.PI) / 180.0 // ��������������������������������������������������� }, // ��������������������������������������������������������������������������������������� - GetDistance(lat1, lng1, lat2, lng2) { + GetDistance (lat1, lng1, lat2, lng2) { var radLat1 = this.Rad(lat1) var radLat2 = this.Rad(lat2) var a = radLat1 - radLat2 @@ -1066,7 +1168,7 @@ return s }, // ��������������� - newDate() { + newDate () { var aData = new Date() var month = aData.getMonth() < 9 @@ -1076,7 +1178,7 @@ this.sensorDate = aData.getFullYear() + '-' + month + '-' + date }, // ��������������� - newTime(timeArr) { + newTime (timeArr) { let str = '' let str2 = '' this.sensorTime = [] @@ -1092,7 +1194,7 @@ }) }, // ������������ - dateChange(e) { + dateChange (e) { if (e === null) { this.sensorDate = [] } else { @@ -1107,7 +1209,7 @@ } }, // ��������������������������������� - getTimeAreaData(item) { + getTimeAreaData (item) { // this.asideData.uavTimeFly = [] this.loading = true this.$request({ @@ -1134,19 +1236,19 @@ }) }, // ������������������ - handleChange(val) { + handleChange (val) { // console.log(val, 222) }, // ��������������������������������������� XY ������ map.lngLatToGeodeticCoord // ������radio - selectRedio(item) { + selectRedio (item) { this.map.remove(this.textMarkers.markers) this.textMarkers.markers = [] this.map.remove(this.Layler) this.addLayers(item) }, // ��������������� - getFlyData(item, index, mac) { + getFlyData (item, index, mac) { // for (var i = 0; i < this.xie.date.length; i++) { // this.xie.date[i].flyLat = this.xie.date[i].flyLat + ' ��'.toString() // this.xie.date[i].flyLon = this.xie.date[i].flyLon + ' ��'.toString() @@ -1195,7 +1297,7 @@ }) }, // ������������������������������������������ - getDate() { + getDate () { this.$request({ url: '/uav/queryDate', method: 'get', @@ -1224,11 +1326,54 @@ } }) }, - initStart(res) { + initDataParams (res) { + const filteredObject = {} + for (let key in res) { + if (key.includes(this.sensorKey)) { + filteredObject[key] = res[key] + } + } + console.log('filteredObject', filteredObject) + + let options = { + MergeAvg: '������������������', + MergedHighest: '���������������������', + MergedLowest: '���������������������', + NotMergedAvg: '���������������������', + NotMergedHighest: '������������������������', + NotMergedLowest: '������������������������' + } + + let notMergedKeys = Object.keys(filteredObject).filter(k => k.match(/(NotMergedHighest|NotMergedLowest|NotMergedAvg)/i)) + let mergedKeys = Object.keys(filteredObject).filter(k => !k.match(/(NotMergedHighest|NotMergedLowest|NotMergedAvg)/i)) + + this.temMergeDataList = Object.keys(options).reduce((acc, key) => { + let valueKey = mergedKeys.find(k => k.toLowerCase().includes(key.toLowerCase())) + if (!valueKey && notMergedKeys.length) { + valueKey = notMergedKeys.find(k => k.toLowerCase().includes(key.replace('NotMerged', '').toLowerCase())) + } + if (valueKey) { + acc.push({ + key: key, + name: options[key], + value: filteredObject[valueKey] + }) + } + return acc + }, []) + + console.log(this.temMergeDataList) + }, + initStart (res) { + console.log('res', res) this.abc += 1 const that = this + if (res) this.initDataParams(res[0]) if (!res) { that.map = new BMapGL.Map('map_container') + console.log('BMapGL', BMapGL) + console.log('BMapGL', BMapGL) + console.log('window', window.BMapGL) that.map.enableScrollWheelZoom(true) // ������������������������������������������������������s that.map.setMapType(BMAP_EARTH_MAP) // ��������������������������������� that.map.setDisplayOptions({ @@ -1329,7 +1474,7 @@ // ��������������������������������� // if (!that.showPoints) { // console.log(111) - // that.map = new BMapGL.Map('map_container') + // that.map = new window.BMapGL.Map('map_container') // } // that.map.enableScrollWheelZoom(true) // ������������������������������������������������������s // that.map.setMapType(BMAP_EARTH_MAP) // ��������������������������������� @@ -1350,7 +1495,7 @@ // building: true, // ������������������ // poiText: false, // ������poi������ // }) - // that.map.addControl(new BMapGL.NavigationControl3D()) // ������3d������ + // that.map.addControl(new window.BMapGL.NavigationControl3D()) // ������3d������ if (this.responseJSON.length === 0) { showNoPoints() } @@ -1383,7 +1528,7 @@ // draw(that.sensor, that.viewType, that.carMac) // drawLine()// ������(���������������������) // drawStartAndEnd() // ��������������������� - function draw(sensor, type, carMac) { + function draw (sensor, type, carMac) { var levels = getGrading(sensor, type, carMac) $.each(levels, function (index, value) { var color = value.color @@ -1411,7 +1556,7 @@ } // ��������������������������������� - function drawPolygon(sensor) { + function drawPolygon (sensor) { $.each(that.showPoints, function (item, point) { var sw = getPoint(225, point.lng, point.lat, that.distance) var ne = getPoint(45, point.lng, point.lat, that.distance) @@ -1426,12 +1571,12 @@ new BMapGL.Point(sw.lng, ne.lat), // ��������� ], { - strokeWeight: 0.1, //������������������,������������������ + strokeWeight: 0.1, // ������������������,������������������ // strokeOpacity: 0.0, //������������������ - fillColor: color, //��������������������� - fillOpacity: 0.8, //������������������������0~1������ - strokeColor: 'black', //������������������ - strokeStyle: 'solid', //������������������solid���dashed��� + fillColor: color, // ��������������������� + fillOpacity: 0.8, // ������������������������0~1������ + strokeColor: 'black', // ������������������ + strokeStyle: 'solid', // ������������������solid���dashed��� } ) that.map.addOverlay(polygon) @@ -1441,7 +1586,7 @@ } // ��������������������� - function drawStartAndEnd() { + function drawStartAndEnd () { var startIcon = new BMapGL.Icon( require('@/assets/images/start.png'), new BMapGL.Size(48, 48) @@ -1466,7 +1611,7 @@ } // ��������������������� - function drawLine() { + function drawLine () { var data = [] var points = [] $.each(trackPoints, function (index, value) { @@ -1493,7 +1638,7 @@ } // ������������>=size���������points - function getShowPoints(size) { + function getShowPoints (size) { var points = [] points.push(trackPoints[0]) for (var i = 1; i < trackPoints.length; i++) { @@ -1517,7 +1662,7 @@ } // ��������������������������������������� - function getPoint(angle, lng, lat, distance) { + function getPoint (angle, lng, lat, distance) { var EARTH_RADIUS = 6378137 // ������������������m // ��������������������������������������� var ra = distance / EARTH_RADIUS @@ -1542,7 +1687,7 @@ return new BMapGL.Point(lng, lat) } - function getGrading(sensor, type, carMac) { + function getGrading (sensor, type, carMac) { var levels = [] var level0 = {} var level1 = {} @@ -1690,7 +1835,7 @@ levels.push(level0, level1, level2, level3, level4, level5, level6) return levels } - function getColorAndLevel(senosor, data) { + function getColorAndLevel (senosor, data) { var levelData = that.sensorTableData var colorAndLevel = {} var color @@ -1889,7 +2034,7 @@ } // point���������label������ - function setLabelStyle(content, point) { + function setLabelStyle (content, point) { var label = new BMapGL.Label( "<span class='my-maptip'>" + content + '<br /><span>', // ���lable������������ { @@ -1916,7 +2061,7 @@ } // ������������,������������������ - function showNoPoints() { + function showNoPoints () { that.map.centerAndZoom('���������', 17) setTimeout(function () { document.getElementById('cpm').style.display = 'block' @@ -1935,7 +2080,7 @@ }) // var that = this - function clickChange() { + function clickChange () { $('.carTop').on('click', () => { // console.log('���������') that.view.removeAllLayers() @@ -1965,7 +2110,7 @@ clickChange() } }, - changeCode(value) { + changeCode (value) { switch (value) { case 'PM2.5': this.sensorKey = 'a34004' @@ -2007,7 +2152,22 @@ } </script> -<style lang="scss" > +<style lang="scss" scoped> +.main-container { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-orient: vertical; + -webkit-box-direction: normal; + -ms-flex-flow: column; + flex-flow: column; + min-height: 100%; + -webkit-transition: margin-left 0.28s; + transition: margin-left 0.28s; + margin-left: 210px; + position: relative; + height: 100%; +} /deep/.BMap_cpyCtrl { display: none; } @@ -2182,20 +2342,7 @@ /deep/.inputNum { width: 4% !important; } -.dateArrClass { - position: relative; -} -.dateArrClass > div ::after { - content: ''; - position: absolute; - right: 8px; - top: 23px; - width: 5px; - height: 5px; - border-radius: 50%; - z-index: 999; - background-color: #f40; -} + .numss { width: 700px; background-color: white; @@ -2242,13 +2389,7 @@ width: 20%; } } -.jlpMySelectPopper.el-picker-panel { - width: 280px; - height: 330px; -} -.jlpMySelectPopper.el-date-picker table { - width: 88%; -} + .BMap_cpyCtrl { display: none; } @@ -2266,4 +2407,42 @@ .el-scrollbar__wrap { overflow-x: hidden; } -</style> \ No newline at end of file +.dataParameter{ + background-color: rgba(192, 192, 192, 0.4); + position: absolute; + bottom: 0px; + padding: 10px; + color: #000; + font-size: 16px; + cursor: pointer; + display: flex; + .item{ + margin: 0px; + padding: 0px; + } +} +</style> +<style > +.jlpMySelectPopper.el-picker-panel { + width: 280px; + height: 330px; +} +.jlpMySelectPopper.el-date-picker table { + width: 88%; +} +.dateArrClass { + position: relative; +} +.dateArrClass > div ::after { + content: ''; + position: absolute; + right: 8px; + top: 23px; + width: 5px; + height: 5px; + border-radius: 50%; + z-index: 999; + background-color: #f40; +} + +</style> -- Gitblit v1.8.0