src/api/dataAnalysisApi.js
@@ -10,5 +10,11 @@ return $http .get(`air/analysis/pollution/trace`, { params: { missionCode } }) .then((res) => res.data); }, fetchPollutionTraceHistory(missionCode) { return $http .get(`air/analysis/pollution/trace/history`, { params: { missionCode } }) .then((res) => res.data); } }; src/assets/logo.svg
@@ -1 +1,4 @@ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 261.76 226.69"><path d="M161.096.001l-30.225 52.351L100.647.001H-.005l130.877 226.688L261.749.001z" fill="#41b883"/><path d="M161.096.001l-30.225 52.351L100.647.001H52.346l78.526 136.01L209.398.001z" fill="#34495e"/></svg> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 261.76 226.69"> <path d="M161.096.001l-30.225 52.351L100.647.001H-.005l130.877 226.688L261.749.001z" fill="#41b883" /> <path d="M161.096.001l-30.225 52.351L100.647.001H52.346l78.526 136.01L209.398.001z" fill="#34495e" /> </svg> src/assets/wdr.svg
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,6 @@ <svg t="1751598713381" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4696" width="30" height="30"> <path d="M973.824 278.186667l-136.533333-85.333334A34.133333 34.133333 0 0 0 785.066667 221.866667V273.066667H318.122667L88.064 108.885333a34.133333 34.133333 0 0 0-51.541333 40.277334L99.669333 307.2l-63.146666 158.037333A34.133333 34.133333 0 0 0 68.266667 512a34.133333 34.133333 0 0 0 19.797333-6.485333L318.122667 341.333333H477.866667v307.2h-68.266667v341.333334h68.266667v-273.066667h68.266666v273.066667h68.266667V648.533333h-68.266667v-307.2h238.933334v51.2a34.133333 34.133333 0 0 0 17.749333 29.696 34.133333 34.133333 0 0 0 16.384 4.437334 34.133333 34.133333 0 0 0 18.090667-5.12l136.533333-85.333334a34.133333 34.133333 0 0 0 0-58.026666z" p-id="4697" fill="#CCD1D7"></path> </svg> src/components.d.ts
@@ -7,92 +7,93 @@ declare module 'vue' { export interface GlobalComponents { BaseCard: typeof import('./components/BaseCard.vue')['default'] BaseMap: typeof import('./components/map/BaseMap.vue')['default'] CardButton: typeof import('./components/CardButton.vue')['default'] CardDialog: typeof import('./components/CardDialog.vue')['default'] 'CardDialog copy': typeof import('./components/CardDialog copy.vue')['default'] CheckButton: typeof import('./components/common/CheckButton.vue')['default'] ConfigManage: typeof import('./components/map/ConfigManage.vue')['default'] copy: typeof import('./components/CardDialog copy.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'] DataTable: typeof import('./components/monitor/DataTable.vue')['default'] DescriptionsList: typeof import('./components/list/DescriptionsList.vue')['default'] DescriptionsListItem: typeof import('./components/list/DescriptionsListItem.vue')['default'] DeviceCreate: typeof import('./components/device/DeviceCreate.vue')['default'] DeviceManage: typeof import('./components/device/DeviceManage.vue')['default'] ElButton: typeof import('element-plus/es')['ElButton'] ElCascader: typeof import('element-plus/es')['ElCascader'] ElCheckbox: typeof import('element-plus/es')['ElCheckbox'] ElCheckboxGroup: typeof import('element-plus/es')['ElCheckboxGroup'] ElCol: typeof import('element-plus/es')['ElCol'] ElConfigProvider: typeof import('element-plus/es')['ElConfigProvider'] ElDatePicker: typeof import('element-plus/es')['ElDatePicker'] ElDialog: typeof import('element-plus/es')['ElDialog'] ElDivider: typeof import('element-plus/es')['ElDivider'] ElDropdown: typeof import('element-plus/es')['ElDropdown'] ElDropdownItem: typeof import('element-plus/es')['ElDropdownItem'] ElDropdownMenu: typeof import('element-plus/es')['ElDropdownMenu'] ElForm: typeof import('element-plus/es')['ElForm'] ElFormItem: typeof import('element-plus/es')['ElFormItem'] ElIcon: typeof import('element-plus/es')['ElIcon'] ElInput: typeof import('element-plus/es')['ElInput'] ElLink: typeof import('element-plus/es')['ElLink'] ElOption: typeof import('element-plus/es')['ElOption'] ElPagination: typeof import('element-plus/es')['ElPagination'] ElPopover: typeof import('element-plus/es')['ElPopover'] ElRadio: typeof import('element-plus/es')['ElRadio'] ElRadioGroup: typeof import('element-plus/es')['ElRadioGroup'] ElRow: typeof import('element-plus/es')['ElRow'] ElScrollbar: typeof import('element-plus/es')['ElScrollbar'] ElSelect: typeof import('element-plus/es')['ElSelect'] ElSlider: typeof import('element-plus/es')['ElSlider'] ElSpace: typeof import('element-plus/es')['ElSpace'] ElStatistic: typeof import('element-plus/es')['ElStatistic'] ElSwitch: typeof import('element-plus/es')['ElSwitch'] ElTable: typeof import('element-plus/es')['ElTable'] ElTableColumn: typeof import('element-plus/es')['ElTableColumn'] ElTabPane: typeof import('element-plus/es')['ElTabPane'] ElTabs: typeof import('element-plus/es')['ElTabs'] ElTag: typeof import('element-plus/es')['ElTag'] ElText: typeof import('element-plus/es')['ElText'] FactorCheckbox: typeof import('./components/monitor/FactorCheckbox.vue')['default'] FactorLegend: typeof import('./components/monitor/FactorLegend.vue')['default'] FactorRadio: typeof import('./components/monitor/FactorRadio.vue')['default'] FactorTrend: typeof import('./components/monitor/FactorTrend.vue')['default'] GaugeChart: typeof import('./components/chart/GaugeChart.vue')['default'] GridSearch: typeof import('./components/grid/GridSearch.vue')['default'] HistoricalTrajectory: typeof import('./components/animation/HistoricalTrajectory.vue')['default'] MapLocate: typeof import('./components/map/MapLocate.vue')['default'] MapScene: typeof import('./components/map/MapScene.vue')['default'] MapToolbox: typeof import('./components/map/MapToolbox.vue')['default'] MessageBox: typeof import('./components/MessageBox.vue')['default'] MissionEdit: typeof import('./components/mission/MissionEdit.vue')['default'] MissionImport: typeof import('./components/mission/MissionImport.vue')['default'] MissionManage: typeof import('./components/mission/MissionManage.vue')['default'] OptionDevice: typeof import('./components/search/OptionDevice.vue')['default'] OptionLocation: typeof import('./components/search/OptionLocation.vue')['default'] OptionLocation2: typeof import('./components/search/OptionLocation2.vue')['default'] OptionMission: typeof import('./components/search/OptionMission.vue')['default'] OptionPollutionDegree: typeof import('./components/search/OptionPollutionDegree.vue')['default'] OptionTime: typeof import('./components/search/OptionTime.vue')['default'] OptionType: typeof import('./components/search/OptionType.vue')['default'] ProgressLineChart: typeof import('./components/chart/ProgressLineChart.vue')['default'] RealTimeLineChart: typeof import('./components/chart/RealTimeLineChart.vue')['default'] RouterLink: typeof import('vue-router')['RouterLink'] RouterView: typeof import('vue-router')['RouterView'] SceneSearch: typeof import('./components/scene/SceneSearch.vue')['default'] SceneTable: typeof import('./components/scene/SceneTable.vue')['default'] SearchBar: typeof import('./components/search/SearchBar.vue')['default'] SliderBar: typeof import('./components/SliderBar.vue')['default'] TrajectoryState: typeof import('./components/animation/TrajectoryState.vue')['default'] VehicleData: typeof import('./components/monitor/VehicleData.vue')['default'] WeatherData: typeof import('./components/monitor/WeatherData.vue')['default'] WeatherDataCopy: typeof import('./components/monitor/WeatherData-copy.vue')['default'] BaseCard: (typeof import('./components/BaseCard.vue'))['default']; BaseMap: (typeof import('./components/map/BaseMap.vue'))['default']; CardButton: (typeof import('./components/CardButton.vue'))['default']; CardDialog: (typeof import('./components/CardDialog.vue'))['default']; 'CardDialog copy': (typeof import('./components/CardDialog copy.vue'))['default']; CheckButton: (typeof import('./components/common/CheckButton.vue'))['default']; ConfigManage: (typeof import('./components/map/ConfigManage.vue'))['default']; copy: (typeof import('./components/monitor/WeatherData_Old.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']; DataTable: (typeof import('./components/monitor/DataTable.vue'))['default']; DescriptionsList: (typeof import('./components/list/DescriptionsList.vue'))['default']; DescriptionsListItem: (typeof import('./components/list/DescriptionsListItem.vue'))['default']; DeviceCreate: (typeof import('./components/device/DeviceCreate.vue'))['default']; DeviceManage: (typeof import('./components/device/DeviceManage.vue'))['default']; ElButton: (typeof import('element-plus/es'))['ElButton']; ElCascader: (typeof import('element-plus/es'))['ElCascader']; ElCheckbox: (typeof import('element-plus/es'))['ElCheckbox']; ElCheckboxGroup: (typeof import('element-plus/es'))['ElCheckboxGroup']; ElCol: (typeof import('element-plus/es'))['ElCol']; ElConfigProvider: (typeof import('element-plus/es'))['ElConfigProvider']; ElDatePicker: (typeof import('element-plus/es'))['ElDatePicker']; ElDialog: (typeof import('element-plus/es'))['ElDialog']; ElDivider: (typeof import('element-plus/es'))['ElDivider']; ElDropdown: (typeof import('element-plus/es'))['ElDropdown']; ElDropdownItem: (typeof import('element-plus/es'))['ElDropdownItem']; ElDropdownMenu: (typeof import('element-plus/es'))['ElDropdownMenu']; ElForm: (typeof import('element-plus/es'))['ElForm']; ElFormItem: (typeof import('element-plus/es'))['ElFormItem']; ElIcon: (typeof import('element-plus/es'))['ElIcon']; ElInput: (typeof import('element-plus/es'))['ElInput']; ElLink: (typeof import('element-plus/es'))['ElLink']; ElOption: (typeof import('element-plus/es'))['ElOption']; ElPagination: (typeof import('element-plus/es'))['ElPagination']; ElPopover: (typeof import('element-plus/es'))['ElPopover']; ElRadio: (typeof import('element-plus/es'))['ElRadio']; ElRadioGroup: (typeof import('element-plus/es'))['ElRadioGroup']; ElRow: (typeof import('element-plus/es'))['ElRow']; ElScrollbar: (typeof import('element-plus/es'))['ElScrollbar']; ElSelect: (typeof import('element-plus/es'))['ElSelect']; ElSlider: (typeof import('element-plus/es'))['ElSlider']; ElSpace: (typeof import('element-plus/es'))['ElSpace']; ElStatistic: (typeof import('element-plus/es'))['ElStatistic']; ElSwitch: (typeof import('element-plus/es'))['ElSwitch']; ElTable: (typeof import('element-plus/es'))['ElTable']; ElTableColumn: (typeof import('element-plus/es'))['ElTableColumn']; ElTabPane: (typeof import('element-plus/es'))['ElTabPane']; ElTabs: (typeof import('element-plus/es'))['ElTabs']; ElTag: (typeof import('element-plus/es'))['ElTag']; ElText: (typeof import('element-plus/es'))['ElText']; FactorCheckbox: (typeof import('./components/monitor/FactorCheckbox.vue'))['default']; FactorLegend: (typeof import('./components/monitor/FactorLegend.vue'))['default']; FactorRadio: (typeof import('./components/monitor/FactorRadio.vue'))['default']; FactorTrend: (typeof import('./components/monitor/FactorTrend.vue'))['default']; GaugeChart: (typeof import('./components/chart/GaugeChart.vue'))['default']; GridSearch: (typeof import('./components/grid/GridSearch.vue'))['default']; HistoricalTrajectory: (typeof import('./components/animation/HistoricalTrajectory.vue'))['default']; MapLocate: (typeof import('./components/map/MapLocate.vue'))['default']; MapScene: (typeof import('./components/map/MapScene.vue'))['default']; MapToolbox: (typeof import('./components/map/MapToolbox.vue'))['default']; MessageBox: (typeof import('./components/MessageBox.vue'))['default']; MissionEdit: (typeof import('./components/mission/MissionEdit.vue'))['default']; MissionImport: (typeof import('./components/mission/MissionImport.vue'))['default']; MissionManage: (typeof import('./components/mission/MissionManage.vue'))['default']; OptionDevice: (typeof import('./components/search/OptionDevice.vue'))['default']; OptionLocation: (typeof import('./components/search/OptionLocation.vue'))['default']; OptionLocation2: (typeof import('./components/search/OptionLocation2.vue'))['default']; OptionMission: (typeof import('./components/search/OptionMission.vue'))['default']; OptionPollutionDegree: (typeof import('./components/search/OptionPollutionDegree.vue'))['default']; OptionTime: (typeof import('./components/search/OptionTime.vue'))['default']; OptionType: (typeof import('./components/search/OptionType.vue'))['default']; ProgressLineChart: (typeof import('./components/chart/ProgressLineChart.vue'))['default']; RealTimeLineChart: (typeof import('./components/chart/RealTimeLineChart.vue'))['default']; RouterLink: (typeof import('vue-router'))['RouterLink']; RouterView: (typeof import('vue-router'))['RouterView']; SceneSearch: (typeof import('./components/scene/SceneSearch.vue'))['default']; SceneTable: (typeof import('./components/scene/SceneTable.vue'))['default']; SearchBar: (typeof import('./components/search/SearchBar.vue'))['default']; SliderBar: (typeof import('./components/SliderBar.vue'))['default']; 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_Old: (typeof import('./components/monitor/WeatherData_Old.vue'))['default']; WeatherDataCopy: (typeof import('./components/monitor/WeatherData-copy.vue'))['default']; } export interface ComponentCustomProperties { vLoading: typeof import('element-plus/es')['ElLoadingDirective'] vLoading: (typeof import('element-plus/es'))['ElLoadingDirective']; } } src/components/monitor/FactorIconText.vue
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,72 @@ <template> <el-row justify="start" class="wrap"> <el-col :span="6"> <el-space direction="vertical" :size="0"> <font-awesome-icon v-if="faIcon" :icon="faIcon" class="fa-icon-size" /> <component v-if="elIcon" class="el-icon-size" :is="elIcon"></component> <img v-if="img" :src="img" class="icon-size" /> <el-text class="factor-text">{{ label }}</el-text> </el-space> </el-col> <el-col :span="18"> <el-space direction="vertical" :size="0"> <div> <el-text class="factor-number">{{ value }}</el-text> <el-text class="factor-unit" ><sub>{{ unit }}</sub></el-text > </div> <el-text class="factor-text">{{ des }}</el-text> </el-space> <!-- <div > <el-text class="factor-number">{{ value }}</el-text> <el-text class="factor-unit" ><sub>{{ unit }}</sub></el-text > </div> --> </el-col> </el-row> </template> <script setup> defineProps({ faIcon: String, elIcon: String, img: String, svg: String, label: String, value: String || Number, unit: String, des: String }); </script> <style scoped> .wrap { /* border: 1px solid white; */ width: 120px; } .factor-text { color: whitesmoke; font-size: 9px; } .factor-number { color: whitesmoke; font-size: 20px; line-height: 30px; padding-left: 2px; } .factor-unit { color: whitesmoke; font-size: 12px; margin-left: 2px; } .fa-icon-size { width: 26px; height: 26px; padding: 2px; } .el-icon-size { width: 30px; height: 30px; } </style> src/components/monitor/FactorLegend.vue
@@ -1,19 +1,31 @@ <template> <BaseCard> <transition name="el-zoom-in-left" @before-enter="onBeforeEnter" @after-leave="onAfterLeave" > <BaseCard v-show="show"> <template #content> <el-row justify="space-between" align="middle"> <el-row align="middle"> <img src="@/assets/mipmap/data_chart.png" class="ff-img m-r-4" /> <span>èµ°èªå¾ä¾</span> <span v-if="factor.factorName">ï¼{{ factor.factorName }}ï¼</span> </el-row> <span>{{ factor.factorName }}</span> <span @click="show = !show" class="btn-show"> <el-icon v-if="show"><ArrowLeftBold /></el-icon> <el-icon v-else><ArrowRightBold /></el-icon> </span> </el-row> <div v-for="(item, index) in legends" :key="index" class="flexbox align-items margin-top" > <div class="rectangle" :style="'background-color: ' + item.color"></div> <div class="rectangle" :style="'background-color: ' + item.color" ></div> <el-row v-if="item.max"> <span class="w-40 text-right">{{ item.min }}</span> <span class="w-20 text-center">~</span> @@ -41,6 +53,16 @@ </div> </template> </BaseCard> </transition> <BaseCard v-show="btnShow"> <template #content> <span @click="show = !show" class="btn-show"> <img src="@/assets/mipmap/data_chart.png" class="ff-img m-r-4" /> <el-icon v-if="show"><ArrowLeftBold /></el-icon> <el-icon v-else><ArrowRightBold /></el-icon> </span> </template> </BaseCard> </template> <script> @@ -60,7 +82,9 @@ return { // ç»å¾æ¨¡å¼ï¼false: æ 忍¡å¼ï¼trueï¼å¨ææ¨¡å¼ legendType: false, legends: [] legends: [], show: true, btnShow: false }; }, watch: { @@ -149,6 +173,12 @@ this.factor.max ); }); }, onBeforeEnter() { this.btnShow = false; }, onAfterLeave() { this.btnShow = true; } } }; @@ -166,4 +196,10 @@ --el-switch-on-color: #1f9956; --el-switch-off-color: #8b8b8b; } .btn-show { cursor: pointer; } .btn-show:hover { color: #23dad1; } </style> src/components/monitor/FactorRadio.vue
@@ -1,11 +1,32 @@ <template> <BaseCard> <transition name="el-zoom-in-left" @before-enter="onBeforeEnter" @after-leave="onAfterLeave" > <BaseCard v-show="show" direction="left"> <template #content> <!-- <el-collapse-transition> --> <el-radio-group v-model="radio" size="default" @change="handleChange"> <el-radio v-for="(item, i) in options" :key="i" :value="item.value">{{ item.label }}</el-radio> </el-radio-group> <!-- </el-collapse-transition> --> <span @click="show = !show" class="btn-show"> <el-icon v-if="show"><ArrowLeftBold /></el-icon> <el-icon v-else><ArrowRightBold /></el-icon> </span> </template> </BaseCard> </transition> <BaseCard v-show="btnShow"> <template #content> <el-row @click="show = !show" class="btn-show"> <font-awesome-icon icon="fa-check-circle" /> <el-icon v-if="show"><ArrowLeftBold /></el-icon> <el-icon v-else><ArrowRightBold /></el-icon> </el-row> </template> </BaseCard> </template> @@ -30,7 +51,9 @@ emits: ['change', 'update:modelValue'], data() { return { radio: defaultOptions(TYPE0).value radio: defaultOptions(TYPE0).value, show: true, btnShow: false }; }, computed: { @@ -42,12 +65,12 @@ deviceType(nV, oV) { if (nV != oV) { this.radio = this.options[0].value; this.$emit('update:modelValue', this.radio) this.$emit('update:modelValue', this.radio); } }, modelValue(nV, oV){ if (nV != oV) { this.radio = nV this.radio = nV; } } }, @@ -55,17 +78,31 @@ handleChange(value) { const item = this.options.find((v) => v.value == value); this.$emit('change', item.value, item); this.$emit('update:modelValue', item.value) this.$emit('update:modelValue', item.value); // todo å°å¾3då¾å忢å±ç¤ºçæµå å }, onBeforeEnter() { this.btnShow = false; }, onAfterLeave() { this.btnShow = true; } } }; </script> <style scoped> .el-radio { :deep(.el-radio) { --el-radio-text-color: white; --el-color-primary: #23dad1; margin-right: 10px; height: initial; } .btn-show { cursor: pointer; padding: 4px 0; } .btn-show:hover { color: #23dad1; } </style> src/components/monitor/FactorTrend.vue
@@ -1,7 +1,8 @@ <template> <BaseCard size="medium" direction="left"> <template #content> <el-scrollbar height="calc(49vh - var(--bevel-length-2))" always> <DashBoard ref="dashBoardRef" :factor-datas="factorDatas"></DashBoard> <el-scrollbar :height="height" always> <div v-for="item in seriesList" :key="item.key"> <el-row v-show="selectFactorType.includes(item.series.key)" @@ -34,8 +35,10 @@ import { checkboxOptions } from '@/constant/checkbox-options'; import { factorName } from '@/constant/factor-name'; import { factorUnit } from '@/constant/factor-unit'; import DashBoard from '@/views/realtimemode/component/DashBoard.vue'; export default { components: { DashBoard }, props: { loading: Boolean, factorDatas: FactorDatas, @@ -56,16 +59,13 @@ }, data() { return { height: 'calc(99vh - var(--bevel-length-2))', xAxis: [], allSeries: new Map(), seriesList: [] }; }, computed: { // factorTypes() { // return checkboxOptions(this.deviceType); // } }, computed: {}, watch: { factorDatas: { handler() { @@ -165,7 +165,16 @@ getUnit(label) { // fixeme 2024.5.15 ä¿®å¤COå±ç¤ºåä½ååå§æ°æ®ä¸ä¸è´é®é¢ return label == 'CO' ? 'μg/m³' : factorUnit[label].unit; }, calcHeight() { const h1 = this.$refs.dashBoardRef ? this.$refs.dashBoardRef.$el.offsetHeight : 0; this.height = `calc(98vh - var(--bevel-length-2) - ${h1}px)`; } }, mounted() { this.calcHeight(); } }; </script> src/components/monitor/VehicleData.vue
@@ -1,11 +1,25 @@ <template> <el-row justify="center" class="wrap"> <el-row justify="start" class="wrap"> <!-- <el-space direction="vertical" :size="0"> <el-icon size="30"><Stopwatch /></el-icon> <el-text class="speed-text">SPD</el-text> </el-space> <div> <el-text class="speed-number">{{ speed }}</el-text> <el-text class="speed-unit"><sub>km/h</sub></el-text> </div> --> <FactorIconText elIcon="Odometer" label="SPD" :value="speed" unit="km/h" ></FactorIconText> <!-- <el-form :inline="true"> <el-form-item label="车éï¼" class="tag-2"> {{ speed }}km/h </el-form-item> </el-form> --> <GaugeChart name="车é" :value="speed"></GaugeChart> <!-- <GaugeChart name="车é" :value="speed"></GaugeChart> --> </el-row> </template> <script> src/components/monitor/WeatherData-copy.vue
ÎļþÒÑɾ³ý src/components/monitor/WeatherData.vue
@@ -1,32 +1,38 @@ <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> --> <div> <el-row justify="space-between"> <FactorIconText faIcon="fa-solid fa-temperature-half" label="TEMP" :value="temprature" unit="â" ></FactorIconText> <FactorIconText faIcon="fa-droplet" label="HUM" :value="humidity" unit="%" ></FactorIconText> </el-row> <el-row class="wrap"> <el-form :inline="true" class="form"> <el-form-item label="é£åï¼" class="w-tag"> {{ _windDir }} </el-form-item> <el-form-item label="é£éï¼" class="w-tag"> {{ windSpeed }}m/s </el-form-item> </el-form> <!-- <div class="w-tag">{{ windDirection }}</div> <div class="w-tag">{{ windSpeed }}</div> --> <el-row justify="space-between" class="m-t-4"> <FactorIconText img="/src/assets/wdr.svg" label="WDR" :value="_windDir" ></FactorIconText> <FactorIconText faIcon="fa-wind" label="WS" :value="windSpeed" unit="m/s" ></FactorIconText> </el-row> </div> </template> <script> import { FactorDatas } from '@/model/FactorDatas'; import { windDir } from '@/constant/wind-dir'; import FactorIconText from './FactorIconText.vue'; export default { props: { src/components/monitor/WeatherData_Old.vue
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,106 @@ <template> <div> <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"> {{ _windDir }} </el-form-item> <el-form-item label="é£éï¼" class="w-tag"> {{ windSpeed }}m/s </el-form-item> </el-form> <!-- <div class="w-tag">{{ windDirection }}</div> <div class="w-tag">{{ windSpeed }}</div> --> </el-row> </div> </template> <script> import { FactorDatas } from '@/model/FactorDatas'; import { windDir } from '@/constant/wind-dir'; export default { props: { loading: Boolean, factorDatas: FactorDatas, temprature: { type: String, default: '--' }, humidity: { type: String, default: '--' }, windDirection: { type: String, default: '--' }, windSpeed: { type: String, default: '--' } }, data() { 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'; }, deep: true } }, computed: { _windDir() { return windDir(this.windDirection); } }, 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> src/styles/animation.scss
src/styles/index.scss
@@ -1,2 +1,6 @@ @use './base.scss'; @use './elementUI.scss'; body { font-family: fantasy; } src/views/historymode/HistoryMode.vue
@@ -28,7 +28,6 @@ :factor="factorDatas.factor[factorType]" @change="handleLegendTypeChange" ></FactorLegend> <!-- <SourceTrace></SourceTrace> --> </el-row> <el-row class="historical" justify="center"> <HistoricalTrajectory @@ -53,6 +52,13 @@ :device-type="deviceType" :device-code="deviceCode" ></DataSheet> <SourceTrace class="source-trace" v-model:factorType="factorType" direction="right" mode="history" :mission-code="missionCode" ></SourceTrace> </div> </template> @@ -87,6 +93,7 @@ }, data() { return { missionCode: undefined, // çæµè®¾å¤ç±»å deviceType: TYPE0, // çæµè®¾å¤ç¼å· @@ -227,6 +234,7 @@ this.deviceType = deviceType; this.deviceCode = deviceCode; this.mission = mission; this.missionCode = mission.missionCode; let startTime, endTime; if (timeArray && timeArray.length == 2) { startTime = moment(timeArray[0]).format('YYYY-MM-DD HH:mm:ss'); @@ -307,4 +315,9 @@ left: 0; right: 0; } .source-trace { position: absolute; right: 0; bottom: 0px; } </style> src/views/realtimemode/RealtimeMode.vue
@@ -19,7 +19,7 @@ </el-col> <el-col span="1"> </el-col> </el-row> <DashBoard class="dash-board" :factor-datas="factorDatas"></DashBoard> <!-- <DashBoard class="dash-board" :factor-datas="factorDatas"></DashBoard> --> <RealTimeTrend class="real-time-trend" :factor-datas="factorDatas" @@ -28,6 +28,7 @@ <SourceTrace class="source-trace" v-model:factorType="factorType" :deviceCode="deviceCode" ></SourceTrace> <!-- <PollutedClueItem></PollutedClueItem> --> </div> @@ -219,7 +220,7 @@ <style scoped> .dash-board { position: absolute; left: 0; right: 0; bottom: 0px; } .real-time-trend { @@ -229,7 +230,7 @@ } .source-trace { position: absolute; right: 0; left: 0; bottom: 0px; } </style> src/views/realtimemode/component/DashBoard.vue
@@ -1,8 +1,30 @@ <template> <el-row class="wrap"> <el-col v-show="show" span="10"> <BaseCard> <template #content> <div> <!-- <el-row justify="end"> <el-text class="tag-time" size="default"> <el-icon><Timer /></el-icon> {{ time }} </el-text> </el-row> --> <el-row class="dash-wrap"> <el-col :span="8"> <FactorIconText elIcon="Timer" label="TIME" :value="hms" :des="date" ></FactorIconText> <VehicleData :factor-datas="factorDatas" :speed="speed" class="m-t-4" ></VehicleData> <!-- <el-text class="tag-time" size="default"> <el-icon><Timer /></el-icon> {{ time }} </el-text> --> </el-col> <el-col :span="16"> <WeatherData :factor-datas="factorDatas" :temprature="temprature" @@ -10,17 +32,11 @@ :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> <el-col span="2"> <CardButton name="宿¶çæµ" @click="() => (show = !show)"></CardButton> </el-col> </el-row> <!-- <el-row justify="center"> --> <!-- </el-row> --> </div> </template> <script> import { FactorDatas } from '@/model/FactorDatas'; @@ -41,7 +57,9 @@ windDirection: '--', windSpeed: '--', speed: '0', time: '----/--/--' time: '----/--/--', date: '----/--/--', hms: '--:--:--' }; }, methods: { @@ -61,6 +79,8 @@ this.windSpeed = this.getFactorData(factorDatas, index, '16') + ''; this.speed = this.getFactorData(factorDatas, index, '14', 1); this.time = factorDatas.times[index]; this.date = this.time.split(' ')[0]; this.hms = this.time.split(' ')[1]; } }, mounted() { @@ -69,10 +89,14 @@ }; </script> <style scoped> .dash-wrap { border-bottom: 1px solid rgba(255, 255, 255, 0.445); } .tag-time { color: rgba(255, 255, 255, 0.815); padding: 2px 4px; border: 1px solid white; /* border: 1px solid white; border-radius: 2px; -moz-border-radius: 25px; -moz-border-radius: 25px; */ } </style> src/views/realtimemode/component/DashBoard_Old.vue
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,78 @@ <template> <el-row class="wrap"> <el-col v-show="show" span="10"> <BaseCard> <template #content> <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> <el-col span="2"> <CardButton name="宿¶çæµ" @click="() => (show = !show)"></CardButton> </el-col> </el-row> </template> <script> import { FactorDatas } from '@/model/FactorDatas'; import { realTimeMapAnimation } from '@/utils/map/animation'; export default { props: { deviceType: { type: String }, factorDatas: FactorDatas }, data() { return { show: true, temprature: '--', humidity: '--', windDirection: '--', windSpeed: '--', speed: '0', time: '----/--/--' }; }, methods: { getFactorData(factorDatas, index, key, scale = 10) { const _factor = factorDatas.factor[key]; if (_factor != undefined) { let d = _factor.datas[index].factorData; return Math.round(d * scale) / scale; } else { return '--'; } }, 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> src/views/sourcetrace/SourceTrace.vue
@@ -1,11 +1,11 @@ <template> <el-row> <el-col span="2" class="flex-col"> <el-col v-if="direction == 'right'" span="2" class="flex-col"> <el-row justify="end"> <CardButton direction="left" name="å¨ææº¯æº" @click="() => (show = !show)" @click="handleDisplayChange" ></CardButton> </el-row> <el-row class="flex-col"> @@ -57,6 +57,21 @@ </template> </BaseCard> </el-col> <el-col v-if="direction == 'left'" span="2" class="flex-col"> <el-row justify="start"> <CardButton direction="right" name="å¨ææº¯æº" @click="handleDisplayChange" ></CardButton> </el-row> <el-row class="flex-col"> <PollutedExceptionItem :item="selectedException" @showMarksAndPolygon="showMarksAndPolygon" ></PollutedExceptionItem> </el-row> </el-col> <PollutedClueItem v-model="clueDialog" :item="selectedClue" @@ -72,6 +87,7 @@ import moment from 'moment'; import websocket from '@/api/websocket'; import dataAnalysisApi from '@/api/dataAnalysisApi'; import sector from '@/utils/map/sector'; import mapUtil from '@/utils/map/util'; import { sceneTypes, sceneIcon } from '@/constant/scene-types'; @@ -88,14 +104,25 @@ const NO_SCENE = 'no_scene'; const MODE_REALTIME = 'realtime'; const MODE_HISTORY = 'history'; const props = defineProps({ factorType: String direction: { type: String, default: 'left' }, factorType: String, // 模å¼ï¼realtimeï¼å®æ¶æ¨¡å¼ï¼historyï¼å岿°æ®æ¨¡å¼ mode: { type: String, default: 'realtime' }, missionCode: String, deviceCode: String }); const emits = defineEmits(['update:factorType']); const height = `30vh`; const width = `60vh`; const show = ref(false); const clueDialog = ref(false); @@ -110,6 +137,17 @@ const selectedSceneTypes = ref([]); const sceneOptions = ref([]); function handleDisplayChange() { show.value = !show.value; if ( !show.value && selectedException.value && selectedException.value.showMore ) { showMarksAndPolygon(selectedException.value); } } function scrollToBottom() { const h1 = scrollContentRef.value.clientHeight + 100; setTimeout(() => { @@ -123,9 +161,9 @@ }, 100); } const streams = reactive([]); const streams = ref([]); const filterStreams = computed(() => { return streams.filter((v) => { return streams.value.filter((v) => { // å¤ææ¶æ¯ç±»åæ¯å¦éä¸ const b1 = selectedMsgTypes.value.indexOf(v._type) != -1; let b2, b3; @@ -163,7 +201,7 @@ type2: 0, type3: 0 }; streams.forEach((v) => { streams.value.forEach((v) => { switch (v._type) { case '1': count.type1++; @@ -187,10 +225,15 @@ function dealMsg(data) { const { type, content } = websocketMsgParser.parseMsg(data); const obj = reactive(JSON.parse(content)); if (obj.deviceCode == props.deviceCode) { obj._type = type; dealObj(obj); } } function dealObj(obj) { // 污æçº¿ç´¢ PollutedClue if (type == '1') { if (obj._type == '1') { obj.showMore = false; console.log('污æå¼å¸¸åç: ', obj); @@ -201,13 +244,13 @@ // scrollToTop(); // drawPolygon(obj.pollutedArea); parseChartData(obj); } else if (type == '2') { } else if (obj._type == '2') { // const obj = JSON.parse(content); // obj._type = type; console.log('污æçº¿ç´¢ç»æ: ', obj); obj._timestr = timeFormatter(obj.time); addNewMsg(obj); } else if (type == '3') { } else if (obj._type == '3') { console.log('污ææéåç: ', obj); addNewMsg(obj); parseChartData(obj); @@ -264,7 +307,7 @@ const leftMsgList = []; function addNewMsg(msg, inside) { if (!addNewMsgTask && (leftMsgList.length == 0 || inside)) { streams.splice(0, 0, msg); streams.value.splice(0, 0, msg); addNewMsgTask = setTimeout(() => { clearTimeout(addNewMsgTask); addNewMsgTask = undefined; @@ -278,8 +321,32 @@ } } function fetchPollutionTraceHistory() { dataAnalysisApi.fetchPollutionTraceHistory(props.missionCode).then((res) => { const objList = JSON.parse(res.data); objList.forEach((obj) => { obj._type = obj.msgType + ''; if (obj._type == '1') { obj.showMore = false; show.value = true; parseChartData(obj); } else if (obj._type == '2') { obj._timestr = timeFormatter(obj.time); } else if (obj._type == '3') { parseChartData(obj); } optionsFilte(obj); }); streams.value = objList; }); } onMounted(() => { if (props.mode == MODE_REALTIME) { websocket.registerReceiveEvent(dealMsg); } else if (props.missionCode) { fetchPollutionTraceHistory(); } }); onUnmounted(() => { websocket.removeReceiveEvent(dealMsg); @@ -296,6 +363,15 @@ selectedClue.value._selected = false; } }); watch( () => props.missionCode, (nV, oV) => { if (nV != oV) { fetchPollutionTraceHistory(); } } ); function handleOpen(item) { switch (item._type) { @@ -319,7 +395,7 @@ } function hideAll() { streams.forEach((s) => { streams.value.forEach((s) => { if (polygonMap.has(s.guid)) { s.showMore = false; map.remove(polygonMap.get(s.guid)); @@ -368,6 +444,12 @@ function parseChartData(obj) { // console.log('æçº¿å¾ï¼start'); obj.pollutedData._startTime = moment(obj.pollutedData.startTime).format( 'HH:mm:ss' ); obj.pollutedData._endTime = moment(obj.pollutedData.endTime).format( 'HH:mm:ss' ); const factorDatas = new FactorDatas(); factorDatas.setData(obj.pollutedData.historyDataList, 0, () => { obj._chartOptions = factorDataParser.parseData(factorDatas, [ @@ -383,101 +465,6 @@ function timeFormatter(time) { return moment(time).format('YYYY-MM-DD HH:mm:ss'); } /******************************************************************************************************************** */ /** * æ·»å 䏿¡å·¥ä½æµä¿¡æ¯ * @param {*} data */ const putWorkStream = (data) => { data.substring(); const obj = JSON.parse(data); console.log('sourcetrace: ', obj); obj._statusStr = exceptionStatus(obj.status); if (streams.length == 0) { streams.push(obj); } else { const index = streams.findIndex((v) => { return v.guid == obj.guid; }); if (index != -1) { const old = streams[index]; obj.showMore = old.showMore; old.relatedSceneList.forEach((s) => { const index = obj.relatedSceneList.findIndex((v) => { return v.guid == s.guid; }); if (index == -1) { obj.relatedSceneList.push(s); } }); streams.splice(index, 1, obj); } else { streams.unshift(obj); } show.value = true; } // scrollToBottom(); scrollToTop(); const excObj = streams.find((v) => { return v.factorId + '' == props.factorType; }); if (excObj) { drawSector(excObj); } }; function exceptionStatus(value) { switch (value) { case 1: return 'å¼å¸¸åçä¸'; case 2: return 'å¼å¸¸å·²ç»æ'; default: return 'å¼å¸¸å·²ç»æ'; } } let lastDrawObjGuid; function drawSector(exceptionObj) { emits('update:factorType', exceptionObj.factorId + ''); setTimeout(() => { if (exceptionObj.guid != lastDrawObjGuid) { sector.clearSectorPt(); lastDrawObjGuid = exceptionObj.guid; } // 1. ç»å¶æ°æå½¢åºå const datavo = exceptionObj.midData; const factorDatas = new FactorDatas(); factorDatas.setData([datavo], 0, () => { const pr = sector.drawSectorPt(factorDatas, 0); // è°æ´è§è§å± 䏿¾ç¤º // mapUtil.setCenter(pr.p); drawMarks(exceptionObj.relatedSceneList); }); }, 1000); } let layer = undefined; function drawMarks(sceneList) { if (layer != undefined) { mapUtil.removeViews(layer); // layer = undefined; } if (sceneList.length != 0) { const icons = []; sceneList.forEach((s) => { icons.push(sceneIcon(s.typeId)); }); layer = marks.createLabelMarks(icons, sceneList, true); } } </script> <style scoped> @@ -512,7 +499,7 @@ .scrollbar { width: 400px; /* max-width: 60vw; */ height: 45vh; height: 65vh; /* color: #02ffea; */ padding-right: 10px; } src/views/sourcetrace/component/ClueRecordItem.vue
@@ -12,7 +12,9 @@ <el-text type="primary" size="default"> <el-icon><Timer /></el-icon> {{ item.pollutedData.startTime + ' - ' + item.pollutedData.endTime item.pollutedData._startTime + ' - ' + item.pollutedData._endTime }} </el-text> </el-space> @@ -22,6 +24,7 @@ <el-tag effect="plain" type="info" style="color: black" size="small" hit round @@ -64,7 +67,10 @@ <el-tag type="danger" effect="dark" size="small">线索</el-tag> <el-link type="primary" @click="emits('open')"> 详æ </el-link> </el-row> <el-text type="danger">{{ item.advice }}</el-text> <el-space> <el-icon color="#F56C6C" :size="40"><WarnTriangleFilled /></el-icon> <el-text type="primary">{{ item.advice }}</el-text> </el-space> </div> <el-row v-else-if="item._type == '3'"> <el-col :span="3"> @@ -76,17 +82,20 @@ <el-text type="primary" size="default"> <el-icon><Timer /></el-icon> {{ item.pollutedData.startTime + ' - ' + item.pollutedData.endTime item.pollutedData._startTime + ' - ' + item.pollutedData._endTime }} </el-text> </el-space> <el-link type="primary" @click="emits('open', item)"> 详æ </el-link> <!-- <el-link type="primary" @click="emits('open', item)"> 详æ </el-link> --> </el-row> <div> <el-tag effect="plain" type="info" size="small" style="color: black" hit round class="m-r-4" @@ -158,7 +167,7 @@ function formatDistanceType(value) { switch (value) { case 'TYPE1': return '50米以å '; return '100米以å '; case 'TYPE2': return '50ç±³ - 500米以å '; case 'TYPE3': src/views/sourcetrace/component/PollutedExceptionItem.vue
@@ -27,9 +27,9 @@ <el-icon><Timer /></el-icon> {{ 'åçæ¶æ®µï¼' + item.pollutedData.startTime + item.pollutedData._startTime + ' - ' + item.pollutedData.endTime item.pollutedData._endTime }} </el-text> </div> @@ -46,7 +46,7 @@ </div> --> <div> <el-text type="primary"> <el-icon><BellFilled /></el-icon> <el-icon><Bell /></el-icon> å¼å¸¸ç±»åï¼{{ item.pollutedData.exception }} </el-text> </div> @@ -105,7 +105,8 @@ ></RealTimeLineChart> <!-- </div> --> <div class="border-dashed"> <el-text type="" tag="mark"> <el-icon color="#ffbc58" size="20"><WarningFilled /></el-icon> <el-text type="primary" tag="b"> {{ item.pollutedSource.conclusion }} </el-text> </div> @@ -113,57 +114,6 @@ :show-marks="item.showMore" :scene-list="item.pollutedSource.sceneList" ></SceneTable> <!-- <el-space gap="4"> <el-tag :type="item.status == 1 ? 'danger' : 'info'">{{ item._statusStr }}</el-tag> <el-text type="default">{{ item.exception }}</el-text> </el-space> <el-row gap="4"> <el-text type="primary">åçæ¶é´ï¼</el-text> <el-text type="primary">{{ item.startTime + ' è³ ' }}</el-text> <el-text type="primary">{{ item.status == 1 ? 'å½å' : item.endTime }}</el-text> </el-row> <el-row> <el-col :span="6"> <el-statistic title="å å" :value="item.factorName" /> </el-col> <el-col :span="6"> <el-statistic title="åå¼" :value="item.avg" /> </el-col> <el-col :span="6"> <el-statistic title="å³°å¼" :value="item.max" /> </el-col> <el-col :span="6"> <el-statistic title="è°·å¼" :value="item.min" /> </el-col> </el-row> <el-row justify="space-between"> <el-link type="primary" @click="item.showMore = !item.showMore" > {{ (item.showMore ? 'æ¶èµ·æº¯æºåºæ¯' : 'æ¥ç溯æºåºæ¯') + 'ï¼' + item.relatedSceneList.length + 'ï¼' }} </el-link> <el-link type="primary" @click="drawSector(item)"> æ¥çå¼å¸¸ </el-link> </el-row> <SceneTable v-show="item.showMore" :scene-list="item.relatedSceneList" ></SceneTable> <el-divider /> --> </el-scrollbar> </template> </BaseCard> @@ -233,13 +183,15 @@ padding: 0 4px; /* margin-right: 2px; */ width: 340px; height: 35vh; border-right: 1px solid white; height: 400px; /* border-right: 1px solid white; */ border-radius: 2px; } .border-dashed { /* border: 1px dashed white; */ display: flex; /* align-items: center; */ border: 1px dashed #ffbc58; padding: 0px 1px; margin-bottom: 4px;