Riku
2025-06-04 d0f07e25103d7c7845c3b9534e8c66b5905447c0
动态溯源(待完成)
已修改7个文件
已添加2个文件
116 ■■■■ 文件已修改
src/api/index.js 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components.d.ts 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/CardDialog.vue 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/scene/SceneSearch.vue 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/map/line.js 9 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/realtimemode/RealtimeMode.vue 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/sourcetrace/SourceTrace.vue 29 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/sourcetrace/UnderwayAdvice.vue 44 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/sourcetrace/websocketMsgParser.js 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/index.js
@@ -13,10 +13,10 @@
}
if (debug) {
  ip1 = 'http://192.168.0.110:8084/';
  // ip1 = 'http://localhost:8084/';
  ws = `192.168.0.110:9031`;
  // ws = `localhost:9031`;
  // ip1 = 'http://192.168.0.110:8084/';
  ip1 = 'http://localhost:8084/';
  // ws = `192.168.0.110:9031`;
  ws = `localhost:9031`;
}
const $http = axios.create({
src/components.d.ts
@@ -31,7 +31,6 @@
    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']
@@ -39,7 +38,6 @@
    ElFormItem: typeof import('element-plus/es')['ElFormItem']
    ElIcon: typeof import('element-plus/es')['ElIcon']
    ElInput: typeof import('element-plus/es')['ElInput']
    ElInputNumber: typeof import('element-plus/es')['ElInputNumber']
    ElLink: typeof import('element-plus/es')['ElLink']
    ElOption: typeof import('element-plus/es')['ElOption']
    ElPagination: typeof import('element-plus/es')['ElPagination']
@@ -50,14 +48,12 @@
    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']
src/components/CardDialog.vue
@@ -25,7 +25,7 @@
        </template>
      </BaseCard>
    </template>
    <BaseCard size="medium">
    <BaseCard v-bind="$attrs">
      <template #content>
        <slot></slot>
      </template>
@@ -53,7 +53,7 @@
    modal: {
      type: Boolean,
      default: true
    }
    },
  },
  // emits: ['update:modelValue', 'changed'],
  methods: {
src/components/scene/SceneSearch.vue
@@ -13,6 +13,7 @@
    draggable
    :modal="false"
    width="400px"
    size="medium"
  >
    <template #default>
      <el-row class="scene-table">
src/utils/map/line.js
@@ -20,6 +20,11 @@
  });
}
function drawDirection(path) {
  const polyline = newPolyline(path, '#02ffea');
  map.add(polyline)
}
export default {
  drawLine(fDatas, factor) {
    if (defaultPolylineArr.length > 0) {
@@ -105,5 +110,7 @@
        map.remove(v);
      });
    }
  }
  },
  drawDirection
};
src/views/realtimemode/RealtimeMode.vue
@@ -29,6 +29,7 @@
      class="source-trace"
      v-model:factorType="factorType"
    ></SourceTrace>
    <UnderwayAdvice></UnderwayAdvice>
  </div>
</template>
@@ -43,6 +44,7 @@
import RealTimeTrend from './component/RealTimeTrend.vue';
import DeviceChange from './component/DeviceChange.vue';
import SourceTrace from '@/views/sourcetrace/SourceTrace.vue';
import UnderwayAdvice from '@/views/sourcetrace/UnderwayAdvice.vue';
import { realTimeMapAnimation } from '@/utils/map/animation';
import {
  fetchHistoryData,
@@ -59,7 +61,7 @@
// const mode = 'product';
export default {
  components: { DashBoard, RealTimeTrend, DeviceChange, SourceTrace },
  components: { DashBoard, RealTimeTrend, DeviceChange, SourceTrace, UnderwayAdvice },
  setup() {
    const { loading, fetchData } = useFetchData(10000);
    return { loading, fetchData };
src/views/sourcetrace/SourceTrace.vue
@@ -74,7 +74,7 @@
                  </el-col>
                </el-row>
                <el-row justify="space-between">
                  <el-link
                  <!-- <el-link
                    type="primary"
                    underline
                    @click="showMarksAndPolygon(item)"
@@ -85,16 +85,16 @@
                      item.pollutedSource.sceneList.length +
                      ')'
                    }}
                  </el-link>
                  <!-- <el-link
                  </el-link> -->
                  <el-link
                    type="primary"
                    underline
                    @click="drawPolygon(item.pollutedArea)"
                    @click="showMarksAndPolygon(item)"
                  >
                    å®šä½å¼‚常
                  </el-link> -->
                    {{ item.showMore ? '收起异常' : '定位异常' }}
                  </el-link>
                </el-row>
                <div v-show="item.showMore" style="width: 320px; height: 140px">
                <div style="width: 320px; height: 140px">
                  <RealTimeLineChart
                    v-for="(item1, index1) in item._chartOptions"
                    :key="index1"
@@ -102,7 +102,6 @@
                  ></RealTimeLineChart>
                </div>
                <SceneTable
                  v-show="item.showMore"
                  :show-marks="item.showMore"
                  :scene-list="item.pollutedSource.sceneList"
                ></SceneTable>
@@ -179,10 +178,9 @@
import { map, onMapMounted } from '@/utils/map/index_old';
import { FactorDatas } from '@/model/FactorDatas';
import factorDataParser from '@/utils/chart/factor-data-parser';
import websocketMsgParser from "@/views/sourcetrace/websocketMsgParser.js";
const START_STR = '##';
const SPLIT_STR = '&&';
const END_STR = '%%';
const props = defineProps({
  factorType: String
@@ -219,9 +217,7 @@
let showFirstClueTask;
function dealMsg(data) {
  const [type, content] = data
    .substring(START_STR.length, data.length - END_STR.length)
    .split(SPLIT_STR);
  const {type, content} = websocketMsgParser.parseMsg(data)
  // æ±¡æŸ“线索 PollutedClue
  if (type == '1') {
@@ -251,11 +247,6 @@
    showFirstClueTask = setTimeout(() => {
      showMarksAndPolygon(obj);
    }, 1000);
  }
  // æ±¡æŸ“分析结果 AnalysisResult
  else if (type == '2') {
    const obj = JSON.parse(content);
    console.log('污染分析结果: ', obj);
  }
}
src/views/sourcetrace/UnderwayAdvice.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,44 @@
<template>
  <CardDialog
    v-model="dialogVisible"
    title="走航路线推荐"
    draggable
    :modal="false"
    width="400px"
  >
    <template #default> </template>
    <template #footer> </template>
  </CardDialog>
</template>
<script setup>
import { ref, onMounted, onUnmounted } from 'vue';
import websocket from '@/api/websocket';
import websocketMsgParser from '@/views/sourcetrace/websocketMsgParser.js';
import mapLine from '@/utils/map/line';
const dialogVisible = ref(true);
onMounted(() => {
  websocket.registerReceiveEvent(dealMsg);
});
onUnmounted(() => {
  websocket.removeReceiveEvent(dealMsg);
});
function dealMsg(data) {
  const { type, content } = websocketMsgParser.parseMsg(data);
  // æ±¡æŸ“分析结果 AnalysisResult
  if (type == '2') {
    const obj = JSON.parse(content);
    console.log('污染分析结果: ', obj);
    obj.sortedSceneList;
    obj.time;
    obj.advice;
    obj.direction;
    mapLine.drawDirection(obj.direction.paths.map((v) => [v.first, v.second]));
  }
}
</script>
src/views/sourcetrace/websocketMsgParser.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,13 @@
const START_STR = '##';
const SPLIT_STR = '&&';
const END_STR = '%%';
export default {
  parseMsg(data) {
    const [type, content] = data
      .substring(START_STR.length, data.length - END_STR.length)
      .split(SPLIT_STR);
    return { type, content };
  }
};