From fb876cbc3b21035125668f2db6ee84e47efb544f Mon Sep 17 00:00:00 2001 From: riku <risaku@163.com> Date: 星期日, 12 五月 2024 22:42:22 +0800 Subject: [PATCH] 实时走航模式完成 --- src/utils/map/animation.js | 39 +++++ src/views/historymode/HistoryMode.vue | 7 src/components/monitor/WeatherData.vue | 47 ++++-- src/components.d.ts | 5 src/components/animation/HistoricalTrajectory.vue | 3 src/views/realtimemode/RealtimeMode.vue | 60 ++++++-- src/views/realtimemode/component/DashBoard.vue | 47 ++++++ src/components/core/CoreMenu.vue | 8 src/components/monitor/VehicleData.vue | 10 + src/components/search/OptionDevice.vue | 19 ++ src/components/monitor/WeatherData-copy.vue | 87 ++++++++++++ src/views/realtimemode/component/DeviceChange.vue | 48 ++++++ src/model/FrameAnimation.js | 5 src/components/chart/RealTimeLineChart.vue | 2 14 files changed, 331 insertions(+), 56 deletions(-) diff --git a/src/components.d.ts b/src/components.d.ts index 774c3a8..c38709b 100644 --- a/src/components.d.ts +++ b/src/components.d.ts @@ -11,6 +11,8 @@ BaseMap: typeof import('./components/map/BaseMap.vue')['default'] CardButton: typeof import('./components/CardButton.vue')['default'] CardDialog: typeof import('./components/CardDialog.vue')['default'] + cop: typeof import('./components/monitor/WeatherData.vue')['default'] + copy: typeof import('./components/monitor/WeatherData.vue')['default'] CoreHeader: typeof import('./components/core/CoreHeader.vue')['default'] CoreMenu: typeof import('./components/core/CoreMenu.vue')['default'] DataSummary: typeof import('./components/monitor/DataSummary.vue')['default'] @@ -45,7 +47,6 @@ FactorTrend: typeof import('./components/monitor/FactorTrend.vue')['default'] GaugeChart: typeof import('./components/chart/GaugeChart.vue')['default'] HistoricalTrajectory: typeof import('./components/animation/HistoricalTrajectory.vue')['default'] - LineChart: typeof import('./components/chart/LineChart.vue')['default'] MapToolbox: typeof import('./components/map/MapToolbox.vue')['default'] MIssionCreate: typeof import('./components/mission/MIssionCreate.vue')['default'] MissionImport: typeof import('./components/mission/MissionImport.vue')['default'] @@ -63,6 +64,8 @@ TrajectoryState: typeof import('./components/animation/TrajectoryState.vue')['default'] VehicleData: typeof import('./components/monitor/VehicleData.vue')['default'] WeatherData: typeof import('./components/monitor/WeatherData.vue')['default'] + 'WeatherData cop': typeof import('./components/monitor/WeatherData.vue')['default'] + WeatherDataCopy: typeof import('./components/monitor/WeatherData-copy.vue')['default'] } export interface ComponentCustomProperties { vLoading: typeof import('element-plus/es')['ElLoadingDirective'] diff --git a/src/components/animation/HistoricalTrajectory.vue b/src/components/animation/HistoricalTrajectory.vue index 3224b43..4aaea2d 100644 --- a/src/components/animation/HistoricalTrajectory.vue +++ b/src/components/animation/HistoricalTrajectory.vue @@ -126,6 +126,9 @@ mapAnimation.setOnStopCallback(() => { this.$emit('stop'); }); + }, + unmounted() { + mapAnimation.stop(); } }; </script> diff --git a/src/components/chart/RealTimeLineChart.vue b/src/components/chart/RealTimeLineChart.vue index 562b60f..0cd7b58 100644 --- a/src/components/chart/RealTimeLineChart.vue +++ b/src/components/chart/RealTimeLineChart.vue @@ -66,7 +66,7 @@ justify-content: center; } .line-chart { - width: 300px; + width: 318px; height: 140px; /* border-bottom: 1px solid rgba(255, 255, 255, 0.329); */ } diff --git a/src/components/core/CoreMenu.vue b/src/components/core/CoreMenu.vue index 58050a8..e939907 100644 --- a/src/components/core/CoreMenu.vue +++ b/src/components/core/CoreMenu.vue @@ -57,10 +57,10 @@ name: '璧拌埅鐩戞祴', path: 'rmode' }, - { - name: '缃戞牸鍖栫洃娴�', - path: 'gridmonitor' - } + // { + // name: '缃戞牸鍖栫洃娴�', + // path: 'gridmonitor' + // } // { // name: '鐢ㄧ數閲忕洃娴�', // path: 'emode' diff --git a/src/components/monitor/VehicleData.vue b/src/components/monitor/VehicleData.vue index 97d9f5f..7f7ff70 100644 --- a/src/components/monitor/VehicleData.vue +++ b/src/components/monitor/VehicleData.vue @@ -14,17 +14,21 @@ export default { props: { loading: Boolean, - factorDatas: FactorDatas + factorDatas: FactorDatas, + speed: { + type: Number, + default: 0 + } }, data() { return { - speed: 0 + // speed: 0 }; }, watch: { factorDatas: { handler(nV) { - this.speed = this.lastOne(nV, '14'); + // this.speed = this.lastOne(nV, '14'); }, deep: true } diff --git a/src/components/monitor/WeatherData-copy.vue b/src/components/monitor/WeatherData-copy.vue new file mode 100644 index 0000000..6d53a7e --- /dev/null +++ b/src/components/monitor/WeatherData-copy.vue @@ -0,0 +1,87 @@ +<template> + <el-row class="wrap"> + <el-form :inline="true" class="form"> + <el-form-item label="娓╁害锛�" class="w-tag"> + {{ temprature }} + </el-form-item> + <el-form-item label="婀垮害锛�" class="w-tag"> + {{ humidity }} + </el-form-item> + </el-form> + <!-- <div class="w-tag">{{ temprature }}</div> + <div class="w-tag">{{ humidity }}</div> --> + </el-row> + <el-row class="wrap"> + <el-form :inline="true" class="form"> + <el-form-item label="椋庡悜锛�" class="w-tag"> + {{ windDirection }} + </el-form-item> + <el-form-item label="椋庨�燂細" class="w-tag"> + {{ windSpeed }} + </el-form-item> + </el-form> + <!-- <div class="w-tag">{{ windDirection }}</div> + <div class="w-tag">{{ windSpeed }}</div> --> + </el-row> +</template> +<script> +import { FactorDatas } from '@/model/FactorDatas'; + +export default { + props: { + loading: Boolean, + factorDatas: FactorDatas + }, + data() { + return { + temprature: '--鈩�', + humidity: '--%', + windDirection: '--', + windSpeed: '--m/s', + }; + }, + watch: { + factorDatas: { + handler(nV) { + this.temprature = this.lastOne(nV, '8') + '鈩�'; + this.humidity = this.lastOne(nV, '9') + '%'; + this.windDirection = this.lastOne(nV, '17'); + this.windSpeed = this.lastOne(nV, '16') + 'm/s'; + }, + deep: true + } + }, + methods: { + lastOne(factorDatas, key) { + const f = factorDatas.factor[key]; + if (f) { + const lastIndex = f.datas.length - 1; + return factorDatas.factor[key].datas[lastIndex].factorData; + } else { + return '--'; + } + } + } +}; +</script> +<style scoped> +.w-tag { + padding: 2px 4px; + /* background-color: green; */ + border: 1px solid white; + border-radius: 2px; + -moz-border-radius: 25px; + width: 130px; + /* Old Firefox */ +} + +.form { + display: flex; + gap: 4px; +} + +.el-form-item { + margin-bottom: 4px; + margin-right: 0px !important; +} +</style> diff --git a/src/components/monitor/WeatherData.vue b/src/components/monitor/WeatherData.vue index 85d436a..6609315 100644 --- a/src/components/monitor/WeatherData.vue +++ b/src/components/monitor/WeatherData.vue @@ -2,10 +2,10 @@ <el-row class="wrap"> <el-form :inline="true" class="form"> <el-form-item label="娓╁害锛�" class="w-tag"> - {{ temprature }} + {{ temprature }}鈩� </el-form-item> <el-form-item label="婀垮害锛�" class="w-tag"> - {{ humidity }} + {{ humidity }}% </el-form-item> </el-form> <!-- <div class="w-tag">{{ temprature }}</div> @@ -14,10 +14,10 @@ <el-row class="wrap"> <el-form :inline="true" class="form"> <el-form-item label="椋庡悜锛�" class="w-tag"> - {{ windDirection }} + {{ _windDir }} </el-form-item> <el-form-item label="椋庨�燂細" class="w-tag"> - {{ windSpeed }} + {{ windSpeed }}m/s </el-form-item> </el-form> <!-- <div class="w-tag">{{ windDirection }}</div> @@ -26,31 +26,48 @@ </template> <script> import { FactorDatas } from '@/model/FactorDatas'; +import { windDir } from '../../constant/wind-dir'; export default { props: { loading: Boolean, - factorDatas: FactorDatas + factorDatas: FactorDatas, + temprature: { + type: String, + default: '--' + }, + humidity: { + type: String, + default: '--' + }, + windDirection: { + type: String, + default: '--' + }, + windSpeed: { + type: String, + default: '--' + } }, data() { - return { - temprature: '--鈩�', - humidity: '--%', - windDirection: '--', - windSpeed: '--m/s' - }; + return {}; }, watch: { factorDatas: { handler(nV) { - this.temprature = this.lastOne(nV, '8') + '鈩�'; - this.humidity = this.lastOne(nV, '9') + '%'; - this.windDirection = this.lastOne(nV, '17'); - this.windSpeed = this.lastOne(nV, '16') + 'm/s'; + // this.temprature = this.lastOne(nV, '8') + '鈩�'; + // this.humidity = this.lastOne(nV, '9') + '%'; + // this.windDirection = this.lastOne(nV, '17'); + // this.windSpeed = this.lastOne(nV, '16') + 'm/s'; }, deep: true } }, + computed: { + _windDir() { + return windDir(this.windDirection); + } + }, methods: { lastOne(factorDatas, key) { const f = factorDatas.factor[key]; diff --git a/src/components/search/OptionDevice.vue b/src/components/search/OptionDevice.vue index c16c1f0..6fc1b0a 100644 --- a/src/components/search/OptionDevice.vue +++ b/src/components/search/OptionDevice.vue @@ -31,10 +31,11 @@ deviceList() { const t = this.type ? this.type : '0a'; return [1, 2, 3].map((v) => { - const text = `${t}000000000${v}`; + const label = `${this.getDeviceType(t)}璁惧${v}鍙穈; + const value = `${t}000000000${v}`; return { - label: text, - value: text + label: label, + value: value }; }); } @@ -49,6 +50,18 @@ methods: { handleChange(value) { this.$emit('update:modelValue', value); + }, + getDeviceType(t) { + switch (t) { + case '0a': + return '杞﹁浇'; + case '0b': + return '鏃犱汉鏈�'; + case '0c': + return '鏃犱汉鑸�'; + default: + return '杞﹁浇'; + } } }, mounted() { diff --git a/src/model/FrameAnimation.js b/src/model/FrameAnimation.js index b74d6d9..4ef624d 100644 --- a/src/model/FrameAnimation.js +++ b/src/model/FrameAnimation.js @@ -17,6 +17,7 @@ this.isPause = false; this.isRunning = false; + this.isStop = false; // 鏄惁寮�鍚姩鎬佺粯鍒堕�熷害 this.dynamicSpeed = false; // 姣忎釜浠诲姟鑰楁椂锛堢锛� @@ -29,6 +30,7 @@ start: function () { if (this.intervalFlag != undefined) { this.isPause = false; + this.isStop = false; } else { this.isRunning = true; this._doTask(); @@ -85,7 +87,9 @@ this.isRunning = false; this.isPause = false; + this.isStop = true; this.lastestTime = undefined; + this.speed = 1; }, setOnStopCallback: function (callback) { this.onStopCallback = callback; @@ -127,7 +131,6 @@ t.task(t.data, index, t.count); index += this.speed; - // console.log("_doTask:" + index); }, this.timeout); } }, diff --git a/src/utils/map/animation.js b/src/utils/map/animation.js index 05c8ba7..40fbec8 100644 --- a/src/utils/map/animation.js +++ b/src/utils/map/animation.js @@ -21,6 +21,7 @@ this._fps = this.frameAnimation.fps; // 缁樺埗鍥惧舰缂撳瓨 this.moveViews = {}; + this.clear = true; } MapAnimation.prototype = { @@ -159,6 +160,15 @@ Layer.drawMesh(d, f); // 椋庡悜椋庨�� sector.drawSectorAna(d, start + index); + // 鎵ц鐩戝惉鍑芥暟 + if (typeof that.OnEachFrameCallback === 'function') { + that.OnEachFrameCallback(d, start + index); + } + // 缁樺埗3D鍥惧舰鏃讹紝鏈�灏戦渶瑕�2涓偣鎵嶅彲缁樺埗鍥惧舰 + // 鍥犳姝ゅ绱㈠紩鍙埌鍊掓暟绗簩涓偣灏辩粨鏉燂紝姝ゆ椂鎵ц杩欐浠诲姟缁撴潫鐨勭洃鍚洖璋� + if (typeof that.OnEachTaskEndCallback === 'function') { + that.OnEachTaskEndCallback(d); + } } var pos = d.lnglats_GD[d.lnglats_GD.length - 1]; @@ -200,9 +210,27 @@ this.start(); }, + /** + * 璁剧疆姣忎竴甯х殑鐩戝惉鍑芥暟 + * @param {Function} callback + */ + setOnEachFrameCallback(callback) { + this.OnEachFrameCallback = callback; + }, + + /** + * 璁剧疆姣忎竴娈典换鍔$粨鏉熺殑鐩戝惉鍑芥暟 + * @param {Function} callback + */ + setOnEachTaskEndCallback(callback) { + this.OnEachTaskEndCallback = callback; + }, + /*******************************鍔ㄧ敾浠诲姟閫昏緫 -start ******************************/ start: function () { - sector.clearSector(); + if (this.frameAnimation.isStop) { + sector.clearSector(); + } this.frameAnimation.start(); }, changeSpeed: function (speed) { @@ -214,6 +242,8 @@ stop: function () { this.factorDatas = undefined; this.frameAnimation.addOnNextTasks(undefined); + // this.OnEachFrameCallback = undefined; + // this.OnEachTaskEndCallback = undefined; this.frameAnimation.stop(); }, setOnStopCallback: function (callback) { @@ -242,6 +272,8 @@ /*******************************鍔ㄧ敾浠诲姟閫昏緫 -end ******************************/ _clearMap: function () { + if (!this.clear) return; + var list = []; for (const key in this.moveViews) { list.push(this.moveViews[key]); @@ -386,4 +418,7 @@ } }; -export { MapAnimation }; +const realTimeMapAnimation = new MapAnimation(); +realTimeMapAnimation.clear = false; + +export { realTimeMapAnimation, MapAnimation }; diff --git a/src/views/historymode/HistoryMode.vue b/src/views/historymode/HistoryMode.vue index b40ea8a..e7b2ca9 100644 --- a/src/views/historymode/HistoryMode.vue +++ b/src/views/historymode/HistoryMode.vue @@ -106,12 +106,7 @@ }, // 缁樺埗3D璧拌璺嚎鍥� drawRoadMap(e) { - // this.factorMode = factorMode; - // this.factorType = factorType; - // this.factorName = factorName; this.factorDatas.refreshHeight(this.factorType); - // this.mapMaker.setFactorType(factorType); - // if (!this.mapMaker.runStatus()) { Layer.drawRoadMap(this.factorDatas, e, this.merge, this.setCenter); // } @@ -125,7 +120,7 @@ }); }, drawSector(index) { - // 1. 缁樺埗鎵囧舰鍖哄煙 + // 1. 缁樺埗鏂版墖褰㈠尯鍩� sector.drawSector(this.factorDatas, index); // 2. 缁樺埗瀵硅瘽妗� DialogUtil.openNewWindow(this.factorDatas, index, () => { diff --git a/src/views/realtimemode/RealtimeMode.vue b/src/views/realtimemode/RealtimeMode.vue index 6cc8bfd..1ecbd0a 100644 --- a/src/views/realtimemode/RealtimeMode.vue +++ b/src/views/realtimemode/RealtimeMode.vue @@ -1,6 +1,8 @@ <template> <div class="p-events-none m-t-2"> - <el-row justify="center" align="middle" class="top-wrap"> </el-row> + <el-row justify="center" align="middle" class="top-wrap"> + <DeviceChange @change="onDeviceChange"></DeviceChange> + </el-row> <el-row class="m-t-2"> <FactorRadio :device-type="deviceType" @@ -13,9 +15,7 @@ :factor="factorDatas.factor[factorType]" ></FactorLegend> </el-row> - <el-row class="m-t-2" justify="start"> - <DashBoard :factor-datas="factorDatas"></DashBoard> - </el-row> + <DashBoard class="dash-board" :factor-datas="factorDatas"></DashBoard> <RealTimeTrend class="real-time-trend" :factor-datas="factorDatas" @@ -31,12 +31,13 @@ import monitorDataApi from '@/api/monitorDataApi'; import DashBoard from './component/DashBoard.vue'; import RealTimeTrend from './component/RealTimeTrend.vue'; -import { MapAnimation } from '@/utils/map/animation'; +import DeviceChange from './component/DeviceChange.vue'; +import { realTimeMapAnimation } from '@/utils/map/animation'; -const mapAnimation = new MapAnimation(); +// const mapAnimation = new MapAnimation(); export default { - components: { DashBoard, RealTimeTrend }, + components: { DashBoard, RealTimeTrend, DeviceChange }, setup() { const { loading, fetchData } = useFetchData(10000); return { loading, fetchData }; @@ -54,16 +55,33 @@ allFactorDatas: new FactorDatas() }; }, + watch: { + factorType(nV, oV) { + if (nV != oV) { + realTimeMapAnimation.setFactorType(nV); + } + } + }, computed: { latestTime() { if (this.factorDatas.times.length == 0) { - return '----/--/-- --:--:--'; + return ''; } else { return this.factorDatas.times[this.factorDatas.times.length - 1]; } } }, methods: { + onDeviceChange({ type, deviceCode }) { + this.deviceType = type; + this.deviceCode = deviceCode; + this.clearFetchingTask(); + realTimeMapAnimation.stop(); + this.allFactorDatas.clearData(); + this.factorDatas.clearData(); + this.notFirstFetch = false; + this.fetchRealTimeData(); + }, onFetchData(data) { // todo 鏍规嵁璁惧绫诲瀷鍒囨崲鍦板浘鐩戞祴鍥犲瓙灞曠ず鍗曢�夋銆佹姌绾垮浘澶嶉�夋銆佹暟鎹〃鏍煎閫夋鐨勫洜瀛愮被鍨� // this.deviceType = type; @@ -80,7 +98,7 @@ return monitorDataApi .fetchHistroyData({ deviceCode: this.deviceCode, - startTime: '2021-11-04 09:53:35', + // startTime: '2021-11-04 09:53:35', page, perPage: 100 }) @@ -94,6 +112,7 @@ clearFetchingTask() { if (this.fetchingTask) { clearInterval(this.fetchingTask); + this.fetchingTask = undefined; } }, fetchNextData() { @@ -109,7 +128,7 @@ .fetchNextData({ deviceCode: this.deviceCode, updateTime: this.latestTime, - perPage: 2 + perPage: 10 }) .then((res) => { this.onFetchData(res.data); @@ -126,12 +145,14 @@ this.notFirstFetch = true; } startIndex = startIndex < 0 ? 0 : startIndex; - this.allFactorDatas.addData(dataList, this.drawMode, () => { - mapAnimation.moveAnimation( - this.allFactorDatas, - this.factorType, - startIndex - ); + return new Promise((resolve, reject) => { + this.allFactorDatas.addData(dataList, this.drawMode, () => { + realTimeMapAnimation.moveAnimation( + this.allFactorDatas, + this.factorType, + startIndex + ); + }); }); } }, @@ -140,11 +161,16 @@ }, unmounted() { this.clearFetchingTask(); - mapAnimation.stop(); + realTimeMapAnimation.stop(); } }; </script> <style scoped> +.dash-board { + position: absolute; + left: 0; + bottom: 2px; +} .real-time-trend { position: absolute; right: 0; diff --git a/src/views/realtimemode/component/DashBoard.vue b/src/views/realtimemode/component/DashBoard.vue index 13df5ad..36078e4 100644 --- a/src/views/realtimemode/component/DashBoard.vue +++ b/src/views/realtimemode/component/DashBoard.vue @@ -3,8 +3,17 @@ <el-col v-show="show" span="10"> <BaseCard> <template #content> - <WeatherData :factor-datas="factorDatas"></WeatherData> - <VehicleData :factor-datas="factorDatas"></VehicleData> + <WeatherData + :factor-datas="factorDatas" + :temprature="temprature" + :humidity="humidity" + :wind-direction="windDirection" + :wind-speed="windSpeed" + ></WeatherData> + <VehicleData :factor-datas="factorDatas" :speed="speed"></VehicleData> + <el-row justify="center"> + <div class="tag-time">鏃堕棿锛歿{ time }}</div> + </el-row> </template> </BaseCard> </el-col> @@ -15,6 +24,7 @@ </template> <script> import { FactorDatas } from '@/model/FactorDatas'; +import { realTimeMapAnimation } from '@/utils/map/animation'; export default { props: { @@ -25,8 +35,39 @@ }, data() { return { - show: true + show: true, + temprature: '--', + humidity: '--', + windDirection: '--', + windSpeed: '--', + speed: '0', + time: '----/--/--' }; + }, + methods: { + getFactorData(factorDatas, index, key, scale = 10) { + let d = factorDatas.factor[key].datas[index].factorData; + return Math.round(d * scale) / scale; + }, + refresh(factorDatas, index) { + this.temprature = this.getFactorData(factorDatas, index, '8') + ''; + this.humidity = this.getFactorData(factorDatas, index, '9') + ''; + this.windDirection = this.getFactorData(factorDatas, index, '17') + ''; + this.windSpeed = this.getFactorData(factorDatas, index, '16') + ''; + this.speed = this.getFactorData(factorDatas, index, '14', 1); + this.time = factorDatas.times[index]; + } + }, + mounted() { + realTimeMapAnimation.setOnEachFrameCallback(this.refresh); } }; </script> +<style scoped> +.tag-time { + padding: 2px 4px; + border: 1px solid white; + border-radius: 2px; + -moz-border-radius: 25px; +} +</style> diff --git a/src/views/realtimemode/component/DeviceChange.vue b/src/views/realtimemode/component/DeviceChange.vue new file mode 100644 index 0000000..3772b7d --- /dev/null +++ b/src/views/realtimemode/component/DeviceChange.vue @@ -0,0 +1,48 @@ +<template> + <BaseCard size="middle-s" direction="down"> + <template #content> + <el-form :inline="true"> + <OptionType v-model="formSearch.type"></OptionType> + <OptionDevice + :type="formSearch.type" + v-model="formSearch.deviceCode" + ></OptionDevice> + <el-button type="primary" class="el-button-custom" @click="handleClick"> + 鍒囨崲 + </el-button> + </el-form> + </template> + </BaseCard> +</template> + +<script> +// 鎼滅储妗� +export default { + data() { + return { + formSearch: { + type: '', + deviceCode: '' + } + }; + }, + emits: ['change'], + methods: { + handleClick() { + this.$emit('change', this.formSearch); + } + } +}; +</script> +<style lang="scss"> +.map-date-selector { + display: inline-block; + position: relative; + /* left: 0; + right: 0; + top: 0px; */ + /* padding: 0 4px; */ + /* color: ffffffbd; */ + /* background-color: antiquewhite; */ +} +</style> -- Gitblit v1.9.3