1. 添加溯源清单功能
2. 修复切换至走航监测界面后,之前正在加载的历史数据依旧展示至地图的问题
3. 添加折线图下载图片功能;
4. 添加数据导出功能;
5. 添加设备管理功能;
6. 添加数据弹框和溯源清单开关功能;
7. 优化3D里面的颜色展示逻辑,底部颜色由原来的因子最小值颜色改为当前量级的上一个量级对应的颜色
已修改34个文件
已删除4个文件
已添加3个文件
1506 ■■■■ 文件已修改
src/api/deviceApi.js 11 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/index.js 40 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/sceneInfoApi.js 23 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/border.css 7 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components.d.ts 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/CardDialog.vue 21 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/device/DeviceCreate.vue 85 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/device/DeviceManage.vue 59 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/map/ConfigManage.vue 46 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/map/MapToolbox.vue 33 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/mission/MissionManage.vue 25 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/monitor/DataSummary.vue 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/monitor/DataTable.vue 14 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/scene/SceneSearch.vue 178 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/search/OptionDevice copy.vue 72 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/search/OptionDevice.vue 31 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/search/OptionMission.vue 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/search/OptionType copy.vue 54 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/search/OptionType.vue 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/constant/device-type.js 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/constant/scene-types.js 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/model/Factor.js 9 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/model/Legend.js 27 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/stores/device.js 12 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/stores/scene.js 32 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/stores/toolbox.js 5 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/styles/elementUI.scss 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/chart/chart-option.js 19 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/factor/data.js 35 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/map/3dLayer.js 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/map/dialog.js 53 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/map/marks.js 13 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/map/sector.js 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/map/toolbox.js 25 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/map/util.js 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/HomePage.vue 5 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/LoginPage.vue 13 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/historymode/HistoryMode copy.vue 237 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/historymode/HistoryMode.vue 48 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/realtimemode/RealtimeMode copy.vue 186 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/realtimemode/RealtimeMode.vue 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/deviceApi.js
@@ -4,18 +4,17 @@
 * èµ°èˆªè®¾å¤‡ç›¸å…³æŽ¥å£API
 */
export default {
  fethchDevice({ type, page, pageSize }) {
    let params = `page=${page}&perPage=${pageSize}`;
    params += type ? `&type=${type}` : '';
    return $http.get(`air/device/type?${params}`).then((res) => res.data);
  fethchDevice({ type }) {
    let params = type ? `?&type=${type}` : '';
    return $http.get(`air/device/type${params}`).then((res) => res.data);
  },
  putNewDevice(device) {
    return $http.post(`air/device/create`, device).then((res) => res.data);
    return $http.put(`air/device/create`, device).then((res) => res.data);
  },
  deleteDevice(deviceCode) {
    let params = `deviceCode=${deviceCode}`;
    return $http.post(`air/device/delete?${params}`).then((res) => res.data);
    return $http.delete(`air/device/delete?${params}`).then((res) => res.data);
  }
};
src/api/index.js
@@ -1,7 +1,7 @@
import axios from 'axios';
import { ElMessage } from 'element-plus';
const debug = true;
const debug = false;
let ip1 = 'http://47.100.191.150:9029/';
// console.log(import.meta.env);
@@ -93,4 +93,40 @@
  );
});
export { $http };
// const $http = {
//   get(url) {
//     const controller = new AbortController();
//     return {
//       con: controller,
//       resp: axiosInstance.get(url, { signal: controller.signal })
//     };
//   },
//   put(url, data) {
//     const controller = new AbortController();
//     return {
//       con: controller,
//       resp: axiosInstance.put(url, data, { signal: controller.signal })
//     };
//   },
//   post(url, data) {
//     const controller = new AbortController();
//     return {
//       con: controller,
//       resp: axiosInstance.post(url, data, { signal: controller.signal })
//     };
//   },
//   delete(url) {
//     const controller = new AbortController();
//     return {
//       con: controller,
//       resp: axiosInstance.delete(url, { signal: controller.signal })
//     };
//   }
// };
function resToData(res) {
  res.resp = res.resp.then((res) => res.data);
  return res;
}
export { $http, resToData };
src/api/sceneInfoApi.js
@@ -1,14 +1,27 @@
import { $http } from './index';
/**
 *
 * åœºæ™¯ä¿¡æ¯API接口
 */
export default {
  /**
   * æŸ¥æ‰¾è¡Œæ”¿åŒºåˆ’范围内的某类场景
   * @param {Object} area
   * @returns
   */
  searchScene(area) {
    return $http.post(`scene/find`, area).then((res) => res.data);
  }
  },
  // searchByCoordinate({lng, lat, radius}) {
  //   return $http.post(`scene/find/radius`, mission).then((res) => res.data);
  // },
  /**
   * æŸ¥æ‰¾åŠå¾„范围内的场景
   * @param {Number} lng ç»åº¦ï¼Œé«˜å¾·åœ°å›¾ï¼ˆç«æ˜Ÿåæ ‡ç³»ï¼‰
   * @param {Number} lat ç»´åº¦ï¼Œé«˜å¾·åœ°å›¾ï¼ˆç«æ˜Ÿåæ ‡ç³»ï¼‰
   * @param {Number} radius åŠå¾„,单位米
   * @returns
   */
  searchByCoordinate(lng, lat, radius) {
    let param = `?lng=${lng}&lat=${lat}&radius=${radius}`;
    return $http.post(`scene/find/radius${param}`).then((res) => res.data);
  }
};
src/assets/border.css
@@ -20,8 +20,10 @@
    --border-color: #cac8c8ef;
    --bg-color: #122b54a9;
    --bg-color-2: #122b54e3;
    --select_color: #7dff5d96;
    /* --select_color: #23dad0a2; */
    /* --select_color: #7dff5d96; */
    --select_color: #23dad0a2;
    /* --select_color: #23dad1; */
    /* --font-color: #221f1fc0;
    --border-color: #e5f58eef;
@@ -213,6 +215,7 @@
.ff-content-medium .ff-border-top {
    padding: 8px 8px var(--bevel-length-2) 8px;
    /* padding: 0px 0px var(--bevel-length-2) 0px; */
    -webkit-clip-path:
        polygon(var(--border-width) var(--border-width),
            calc(100% - var(--border-width)) var(--border-width),
src/components.d.ts
@@ -11,7 +11,7 @@
    BaseMap: typeof import('./components/map/BaseMap.vue')['default']
    CardButton: typeof import('./components/CardButton.vue')['default']
    CardDialog: typeof import('./components/CardDialog.vue')['default']
    copy: typeof import('./components/search/OptionType copy.vue')['default']
    ConfigManage: typeof import('./components/map/ConfigManage.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']
@@ -60,17 +60,16 @@
    MissionImport: typeof import('./components/mission/MissionImport.vue')['default']
    MissionManage: typeof import('./components/mission/MissionManage.vue')['default']
    OptionDevice: typeof import('./components/search/OptionDevice.vue')['default']
    'OptionDevice copy': typeof import('./components/search/OptionDevice copy.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']
    OptionTime: typeof import('./components/search/OptionTime.vue')['default']
    OptionType: typeof import('./components/search/OptionType.vue')['default']
    'OptionType copy': typeof import('./components/search/OptionType copy.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']
    SearchBar: typeof import('./components/search/SearchBar.vue')['default']
    SliderBar: typeof import('./components/SliderBar.vue')['default']
    TrajectoryState: typeof import('./components/animation/TrajectoryState.vue')['default']
src/components/CardDialog.vue
@@ -5,8 +5,11 @@
    @closed="handleChange(false)"
    :show-close="false"
    :destroy-on-close="true"
    align-center
    :width="width"
    :draggable="draggable"
    :modal="modal"
    :close-on-click-modal="modal"
    :modal-class="modal ? 'p-events-auto' : ''"
  >
    <template #header="{ close, titleId, titleClass }">
      <BaseCard direction="top-left" borderless="t">
@@ -38,18 +41,30 @@
<script>
export default {
  props: {
    title: String,
    // æ˜¾éšæŽ§åˆ¶
    modelValue: Boolean,
    // æ ‡é¢˜
    title: String,
    // å®½åº¦
    width: {
      type: [String, Number],
      default: '50%'
    },
    // å¯æ‹–拽
    draggable: Boolean,
    // é®ç½©å±‚
    modal: {
      type: Boolean,
      default: true
    }
  },
  emits: ['update:modelValue'],
  emits: ['update:modelValue', 'changed'],
  methods: {
    handleChange(value) {
      this.$emit('update:modelValue', value);
      this.$emit('changed', value);
    }
  }
};
</script>
<style></style>
src/components/device/DeviceCreate.vue
@@ -0,0 +1,85 @@
<template>
  <el-button
    type="primary"
    class="el-button-custom"
    @click="dialogVisible = !dialogVisible"
  >
    æ–°å»ºè®¾å¤‡
  </el-button>
  <CardDialog v-model="dialogVisible" title="新建走航设备">
    <el-form
      :inline="false"
      :model="formObj"
      ref="formRef"
      :rules="rules"
      label-position="right"
      label-width="100px"
    >
      <el-form-item label="设备编号" prop="deviceCode">
        <el-input
          size="small"
          clearable
          v-model="formObj.deviceCode"
          placeholder="设备编号"
        />
      </el-form-item>
      <OptionType :show="true" v-model="formObj.deviceType"></OptionType>
      <el-form-item>
        <el-button
          :disabled="!edit"
          type="primary"
          @click="onSubmit"
          :loading="loading"
          >提交</el-button
        >
        <el-button @click="onCancel">取消</el-button>
      </el-form-item>
    </el-form>
  </CardDialog>
</template>
<script setup>
import { ref, reactive, computed } from 'vue';
import deviceApi from '@/api/deviceApi';
import { useFormConfirm } from '@/composables/formConfirm';
import { useFetchData } from '@/composables/fetchData';
import { useDeviceStore } from '@/stores/device';
const deviceStore = useDeviceStore();
const dialogVisible = ref(false);
const { loading, fetchData } = useFetchData();
const rules = reactive({
  deviceCode: [
    {
      required: true,
      message: '设备编号不能为空',
      trigger: 'blur'
    }
  ]
});
const param = computed(() => {
  return {
    deviceType: formObj.value.deviceType,
    deviceCode: formObj.value.deviceCode
  };
});
// åˆ›å»ºè®¾å¤‡
function createDevice() {
  fetchData(() => {
    return deviceApi.putNewDevice(param.value).then(() => {
      dialogVisible.value = false;
      deviceStore.fetchDevice();
    });
  });
}
const { formObj, formRef, edit, onSubmit, onCancel } = useFormConfirm({
  submit: {
    do: createDevice
  },
  cancel: {
    do: () => {
      dialogVisible.value = false;
    }
  }
});
</script>
<style scoped></style>
src/components/device/DeviceManage.vue
@@ -1,17 +1,21 @@
<template>
  <el-button
  <!-- <el-button
    type="primary"
    icon="Memo"
    class="el-button-custom p-events-auto"
    @click="dialogVisible = !dialogVisible"
  >
    è®¾å¤‡ç®¡ç†
  </el-button>
  <CardDialog v-model="dialogVisible" title="走航设备管理">
    <el-row class="mission-table">
  </el-button> -->
  <CardDialog
    :model-value="modelValue"
    @changed="handleChange"
    title="走航设备管理"
  >
    <el-row class="device-table">
      <el-col :span="20">
        <el-table
          :data="deviceStore.deviceList"
          :data="deviceData"
          table-layout="fixed"
          size="small"
          :show-overflow-tooltip="true"
@@ -28,7 +32,14 @@
            align="center"
            width="50"
          />
          <el-table-column prop="deviceType" label="设备类型" align="center" />
          <el-table-column
            prop="deviceType"
            label="设备类型"
            align="center"
            width="70"
            :formatter="deviceFormatter"
          />
          <el-table-column prop="deviceName" label="设备名称" align="center" />
          <el-table-column prop="deviceCode" label="设备编号" align="center" />
          <el-table-column
            prop="createTime"
@@ -36,7 +47,7 @@
            align="center"
            :formatter="timeFormatter"
          />
          <el-table-column label="管理" width="140" align="center">
          <el-table-column label="管理" width="70" align="center">
            <template #default="{ row }">
              <el-button
                type="primary"
@@ -51,7 +62,7 @@
      </el-col>
      <el-col :span="4" class="flex-col">
        <div>
          <!-- todo è®¾å¤‡åˆ›å»º -->
          <DeviceCreate></DeviceCreate>
        </div>
      </el-col>
    </el-row>
@@ -59,24 +70,27 @@
  <MessageBox
    v-model="msgBoxVisible"
    :on-confirm="onConfirm"
    title="删除走航任务"
    msg="确认是否删除该走航任务"
    title="删除走航设备"
    msg="确认是否删除该走航设备"
    confirmText="删除"
  ></MessageBox>
</template>
<script>
import moment from 'moment';
import deviceApi from '@/api/deviceApi';
import { mapStores } from 'pinia';
import { useDeviceStore } from '@/stores/device';
import { useFetchData } from '@/composables/fetchData';
import { typeName } from '@/constant/device-type';
export default {
  setup() {
    const { loading, fetchData } = useFetchData();
    return { loading, fetchData };
  },
  props: {},
  props: {
    modelValue: Boolean
  },
  emits: ['update:modelValue'],
  data() {
    return {
      dialogVisible: false,
@@ -85,18 +99,37 @@
    };
  },
  computed: {
    ...mapStores(useDeviceStore)
    ...mapStores(useDeviceStore),
    deviceData() {
      return this.deviceStore.getDevice();
    }
  },
  methods: {
    handleChange(value) {
      this.$emit('update:modelValue', value);
    },
    deleteDevice(row) {
      this.onConfirm = () => {
        this.deviceStore.deleteDevice(row.deviceCode);
      };
      this.msgBoxVisible = true;
    },
    // eslint-disable-next-line no-unused-vars
    deviceFormatter(row, col, cellValue, index) {
      return typeName(cellValue);
    },
    // eslint-disable-next-line no-unused-vars
    timeFormatter(row, col, cellValue, index) {
      return moment(cellValue).format('YYYY-MM-DD HH:mm:ss');
    }
  }
};
</script>
<style scoped>
.flex-col {
  display: flex;
  flex-direction: column;
  gap: 4px;
  align-items: flex-end;
}
</style>
src/components/map/ConfigManage.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,46 @@
<template>
  <el-dropdown class="p-events-auto" trigger="click" size="small">
    <el-button type="primary" class="el-button-custom">
      <el-icon class="el-icon--left"><Setting /></el-icon>
      é…ç½®ç®¡ç†
      <el-icon class="el-icon--right"><arrow-down /></el-icon>
    </el-button>
    <template #dropdown>
      <el-dropdown-menu>
        <el-dropdown-item>
          <el-button
            type="info"
            icon="Memo"
            plain
            @click="missionVisible = !missionVisible"
          >
            ä»»åŠ¡ç®¡ç†
          </el-button>
        </el-dropdown-item>
        <el-dropdown-item>
          <el-button
            type="info"
            icon="Cellphone"
            plain
            @click="deviceVisible = !deviceVisible"
          >
            è®¾å¤‡ç®¡ç†
          </el-button>
        </el-dropdown-item>
      </el-dropdown-menu>
    </template>
  </el-dropdown>
  <MissionManage v-model="missionVisible"></MissionManage>
  <DeviceManage v-model="deviceVisible"></DeviceManage>
</template>
<script>
export default {
  data() {
    return {
      missionVisible: false,
      deviceVisible: false
    };
  },
  methods: {}
};
</script>
src/components/map/MapToolbox.vue
@@ -7,7 +7,7 @@
  >
    <el-button type="primary" class="el-button-custom">
      <el-icon class="el-icon--left"><TakeawayBox /></el-icon>
      åœ°å›¾å·¥å…·ç®±
      å·¥å…·ç®±
      <el-icon class="el-icon--right"><arrow-down /></el-icon>
    </el-button>
    <template #dropdown>
@@ -65,14 +65,14 @@
          }
        },
        {
          icon: 'fa fa-compass',
          icon: 'fa fa-crosshairs',
          label: '坐标拾取',
          value: false,
          click: function () {
            this.value = !this.value;
            toolbox.toggleCoorPicking(this.value);
          }
        }
        },
        // {
        //   icon: 'fa fa-compass',
        //   label: '数据标记',
@@ -82,15 +82,24 @@
        //     // todo æ•°æ®æ ‡è®°
        //   }
        // },
        // {
        //   icon: 'fa fa-compass',
        //   label: '数据弹框',
        //   value: true,
        //   click: function () {
        //     this.value = !this.value;
        //     // todo æ•°æ®å¼¹æ¡†
        //   }
        // }
        {
          icon: 'fa fa-comment-alt',
          label: '数据弹框',
          value: true,
          click: function () {
            this.value = !this.value;
            toolbox.toggleDataDialogStatus(this.value);
          }
        },
        {
          icon: 'fa fa-comment-alt',
          label: '溯源清单',
          value: true,
          click: function () {
            this.value = !this.value;
            toolbox.toggleSceneSearch(this.value);
          }
        }
      ]
    };
  },
src/components/mission/MissionManage.vue
@@ -1,13 +1,17 @@
<template>
  <el-button
  <!-- <el-button
    type="primary"
    icon="Memo"
    class="el-button-custom p-events-auto"
    @click="dialogVisible = !dialogVisible"
  >
    ä»»åŠ¡ç®¡ç†
  </el-button>
  <CardDialog v-model="dialogVisible" title="走航任务管理">
  </el-button> -->
  <CardDialog
    :model-value="modelValue"
    @changed="handleChange"
    title="走航任务管理"
  >
    <el-row class="mission-table">
      <el-col :span="20">
        <el-table
@@ -50,14 +54,14 @@
                @click="deleteMission(row)"
                >删除</el-button
              >
              <el-button
              <!-- <el-button
                :loading="row.downloadLoading"
                type="primary"
                size="small"
                class="el-button-custom"
                @click="downloadReport(row)"
                >报告</el-button
              >
              > -->
            </template>
          </el-table-column>
        </el-table>
@@ -102,7 +106,10 @@
    const { loading, fetchData } = useFetchData();
    return { loading, fetchData };
  },
  props: {},
  props: {
    modelValue: Boolean
  },
  emits: ['update:modelValue'],
  data() {
    return {
      dialogVisible: false,
@@ -114,6 +121,9 @@
    ...mapStores(useMissionStore)
  },
  methods: {
    handleChange(value) {
      this.$emit('update:modelValue', value);
    },
    deleteMission(row) {
      this.onConfirm = () => {
        this.missionStore.deleteMission(row.missionCode);
@@ -126,6 +136,7 @@
        .downloadReport(row.missionCode)
        .finally(() => (row.downloadLoading = false));
    },
    // eslint-disable-next-line no-unused-vars
    timeFormatter(row, col, cellValue, index) {
      return moment(cellValue).format('YYYY-MM-DD HH:mm:ss');
    }
@@ -153,6 +164,6 @@
}
.mission-table {
  height: 60vh;
  /* height: 60vh; */
}
</style>
src/components/monitor/DataSummary.vue
@@ -20,7 +20,7 @@
            size="small"
            :show-overflow-tooltip="true"
            border
            row-class-name="t-row"
            row-class-name="t-row-summary"
            cell-class-name="t-cell"
            header-row-class-name="t-header-row"
            header-cell-class-name="t-header-cell"
@@ -136,3 +136,15 @@
  }
};
</script>
<style>
.t-row-summary {
  cursor: auto;
  background-color: transparent !important;
}
</style>
<style scoped>
.el-table {
  --el-table-row-hover-bg-color: transparent;
  --el-table-current-row-bg-color: transparent;
}
</style>
src/components/monitor/DataTable.vue
@@ -56,7 +56,7 @@
    </template>
    <template #footer>
      <el-row justify="space-between" class="p-b-2">
      <el-row justify="space-between" class="p-b-2 one-row">
        <el-button
          :loading="downloadLoading"
          type="primary"
@@ -259,11 +259,17 @@
  }
};
</script>
<style scoped>
.one-row {
  /* background-color: red; */
  flex-wrap: nowrap;
}
</style>
<style>
.el-table {
  --el-table-bg-color: transparent;
  --el-table-row-hover-bg-color: #23dad0a2;
  --el-table-current-row-bg-color: #23dad0a2;
  --el-table-row-hover-bg-color: var(--select_color);
  --el-table-current-row-bg-color: var(--select_color);
  /* --el-table-current-row-bg-color: #7dff5d96; */
  --el-table-text-color: var(--font-color);
}
@@ -284,7 +290,7 @@
.t-header-cell {
  background-color: var(--bg-color-2) !important;
  text-align: center !important;
  /* text-align: center !important; */
  color: white !important;
}
.el-pagination {
src/components/scene/SceneSearch.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,178 @@
<template>
  <!-- <el-button
    type="primary"
    icon="Memo"
    class="el-button-custom p-events-auto"
    @click="dialogVisible = !dialogVisible"
  >
    æº¯æºæ¸…单
  </el-button> -->
  <CardDialog
    v-model="dialogVisible"
    title="溯源清单"
    draggable
    :modal="false"
    width="400px"
  >
    <template #default>
      <el-row class="scene-table">
        <!-- <el-col :span="20"> -->
        <el-table
          :data="sceneStore.sceneList"
          table-layout="fixed"
          size="small"
          :show-overflow-tooltip="true"
          border
          row-class-name="t-row"
          cell-class-name="t-cell"
          header-row-class-name="t-header-row"
          header-cell-class-name="t-header-cell"
          @row-click="handleRowClick"
        >
          <el-table-column type="index" label="#" width="25" />
          <el-table-column
            prop="type"
            label="类型"
            width="55"
            :filters="sceneTypeFilter"
            :filter-method="filterHandler"
          />
          <el-table-column prop="name" label="名称" />
          <!-- <el-table-column prop="location" label="地址" /> -->
          <!-- <el-table-column prop="districtName" label="区县" align="center" /> -->
          <!-- <el-table-column label="管理" width="70" align="center">
            <template #default="{ row }">
              <el-button
                type="primary"
                size="small"
                class="el-button-custom"
                @click="deleteDevice(row)"
                >删除</el-button
              >
            </template>
          </el-table-column> -->
        </el-table>
        <!-- </el-col> -->
      </el-row>
    </template>
    <template #footer>
      <el-row justify="start" align="middle" class="p-b-2 one-row">
        <el-text size="small" type="warning">搜索范围</el-text>
        <el-input
          class="input-radius m-h-2"
          size="small"
          v-model="sceneStore.radius"
          :min="1"
        />
        <el-text size="small" type="warning">
          å…¬é‡Œä»¥å†…,结果{{ sceneStore.sceneList.length }}条</el-text
        >
      </el-row>
    </template>
  </CardDialog>
</template>
<script>
import { sceneTypes, sceneIcon } from '@/constant/scene-types';
import marks from '@/utils/map/marks';
import { useFetchData } from '@/composables/fetchData';
import { mapStores } from 'pinia';
import { useSceneStore } from '@/stores/scene';
import { useToolboxStore } from '@/stores/toolbox';
import MapUtil from '@/utils/map/util';
let layer = undefined;
export default {
  setup() {
    const { loading, fetchData } = useFetchData();
    return { loading, fetchData };
  },
  props: {
    modelValue: Boolean
  },
  emits: ['update:modelValue'],
  data() {
    return {
      dialogVisible: false,
      onConfirm: undefined
    };
  },
  computed: {
    ...mapStores(useSceneStore),
    ...mapStores(useToolboxStore),
    sceneTypeFilter() {
      return sceneTypes()
        .filter((v) => {
          return !v.disabled;
        })
        .map((v) => {
          return { text: v.label, value: v.label };
        });
    }
  },
  watch: {
    dialogVisible(nv) {
      if (layer) {
        if (!nv) {
          MapUtil.removeViews(layer);
        } else {
          MapUtil.addViews(layer);
        }
      }
    },
    'sceneStore.sceneList': {
      handler(nV, oV) {
        if (nV != oV) {
          this.dialogVisible = true;
          this.drawMarks(nV);
        }
      },
      deep: true
    },
    'toolboxStore.sceneSearchStatus': {
      handler(nV) {
        if (!nV) {
          this.dialogVisible = false;
        }
      },
      deep: true
    }
  },
  methods: {
    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, false);
      }
    },
    handleRowClick(row, col, event) {
      MapUtil.setCenter([row.longitude, row.latitude], true);
    },
    filterHandler(value, row, column) {
      const property = column['property'];
      return row[property] === value;
    }
  }
};
</script>
<style scoped>
.scene-table {
  /* background-color: antiquewhite; */
}
.input-radius {
  width: 36px;
  height: 16px;
}
/* .ff-content-medium .ff-border-top {
  padding: 0px 0px var(--bevel-length-2) 0px;
} */
</style>
src/components/search/OptionDevice copy.vue
ÎļþÒÑɾ³ý
src/components/search/OptionDevice.vue
@@ -19,6 +19,8 @@
<script>
import { deviceList } from '@/constant/device-type';
import { mapStores } from 'pinia';
import { useDeviceStore } from '@/stores/device';
export default {
  props: {
@@ -30,25 +32,52 @@
    return {};
  },
  computed: {
    ...mapStores(useDeviceStore),
    deviceOptions() {
      return deviceList(this.type);
      return this.deviceStore.getDevice(this.type).map((v) => {
        return {
          label: v.deviceName,
          value: v.deviceCode
        };
      });
    }
  },
  watch: {
    // type(nV, oV) {
    //   if (nV != oV) {
    //     this.refreshOptions();
    //   }
    // }
    deviceOptions(nV, oV) {
      if (nV != oV) {
        if (nV.length > 0) {
        this.handleChange(nV[0].value);
        }
      }
    }
  },
  methods: {
    fetchDevice() {
      this.deviceStore.fetchDevice().then((res) => {
        if (res.success && res.data.length > 0) {
          this.handleChange(this.deviceOptions[0].value);
        }
      });
    },
    // refreshOptions() {
    //   this.deviceOptions =
    // },
    handleChange(value) {
      this.$emit('update:modelValue', value);
    }
  },
  mounted() {
    if (this.deviceStore.deviceList.length == 0) {
      this.fetchDevice();
    } else {
    this.handleChange(this.deviceOptions[0].value);
  }
  }
};
</script>
<style scoped></style>
src/components/search/OptionMission.vue
@@ -54,7 +54,12 @@
    }
  },
  mounted() {
    if (this.missionStore.missionList.length == 0) {
    this.fetchMission();
    } else {
      this.index = 0;
      this.handleChange(0);
    }
  }
};
</script>
src/components/search/OptionType copy.vue
ÎļþÒÑɾ³ý
src/components/search/OptionType.vue
@@ -1,11 +1,12 @@
<template>
  <el-form-item v-show="isShow" label="类型">
  <el-form-item v-show="show" label="类型">
    <el-select
      :model-value="modelValue"
      @update:model-value="handleChange"
      placeholder="类型"
      size="small"
      class="w-80"
      :disabled="disabled"
    >
      <el-option
        v-for="(s, i) in typeList"
@@ -21,6 +22,14 @@
import { typeList } from '@/constant/device-type';
export default {
  props: {
    disabled: {
      type: Boolean,
      default: import.meta.env.VITE_DATA_MODE == 'jingan'
    },
    show: {
      type: Boolean,
      default: import.meta.env.VITE_DATA_MODE != 'jingan'
    },
    modelValue: String
  },
  emits: ['update:modelValue'],
@@ -30,6 +39,14 @@
      isShow: import.meta.env.VITE_DATA_MODE != 'jingan'
    };
  },
  watch: {
    show: {
      handler(nV) {
        this.isShow = nV;
      },
      immediate: true
    }
  },
  methods: {
    handleChange(value) {
      // todo æ ¹æ®è®¾å¤‡ç±»åž‹åˆ‡æ¢åœ°å›¾è½½å…·çš„图标、
src/constant/device-type.js
@@ -30,6 +30,10 @@
      {
        label: '无人船',
        value: '0c'
      },
      {
        label: '网格化',
        value: '0d'
      }
    ];
  }
@@ -61,4 +65,8 @@
  }
}
export { TYPE0, TYPE1, TYPE2, TYPE3, TYPE4, typeList, deviceList };
function typeName(type) {
  return typeList().find((v) => (v.value = type)).label;
}
export { TYPE0, TYPE1, TYPE2, TYPE3, TYPE4, typeList, typeName, deviceList };
src/constant/scene-types.js
@@ -20,7 +20,7 @@
}
function sceneIcon(type) {
  switch (type) {
  switch (type + '') {
    case '1':
      return scene_1;
    case '4':
src/model/Factor.js
@@ -51,6 +51,7 @@
  this.factorId;
  this.heights = []; //3d地图当前展示坐标点对应的高度数组
  this.colors = []; // 3d地图当前展示坐标点对应的颜色数组
  this.bottomColors = []; //最小值对应的图例色数组
  this.bottomColor; //最小值对应的图例色
  this.min = -1; // å½“前显示的最小值
  this.max = -1; // å½“前显示的最大值
@@ -72,6 +73,7 @@
    this.factorName = options.factorName;
    this.factorId = options.factorId;
    this.colors = options.colors;
    this.bottomColors = options.bottomColors;
    this.bottomColor = options.bottomColor;
    this.standardMin = options.standardMin;
    this.standardMax = options.standardMax;
@@ -125,12 +127,12 @@
    this.heights = [];
    this.colors = [];
    this.datas.forEach((d) => {
      var h = getFactorHeight(d.factorId, d.factorData, [this.min, this.max]);
      const h = getFactorHeight(d.factorId, d.factorData, [this.min, this.max]);
      if (d.factorData == -1) {
        h = -1;
      }
      this.heights.push(h);
      var c = Legend.getColor(
      const c = Legend.getColor(
        this.factorName,
        this.legendType,
        d.factorData,
@@ -138,6 +140,8 @@
        this.max
      );
      this.colors.push(c);
      const b = Legend.getPreviousColor(this.factorName, this.legendType, c);
      this.bottomColors.push(b);
      // this.heights.push(d.factorData)
    });
    this.bottomColor = Legend.getColor(
@@ -182,6 +186,7 @@
      originMax: this.originMax,
      factorName: this.factorName,
      colors: this.colors,
      bottomColors: this.bottomColors,
      bottomColor: this.bottomColor,
      standardMin: this.standardMin,
      standardMax: this.standardMax
src/model/Legend.js
@@ -181,23 +181,42 @@
  },
  /**
   * èŽ·å–å½“å‰é¢œè‰²ä¸Šä¸€ä¸ªç­‰çº§çš„é¢œè‰²
   * @param {*} name
   * @param {*} type
   * @param {*} color
   */
  getPreviousColor(name, type, color) {
    let colors;
    if (type == this.S_TYPE) {
      colors = this._legend_c[name];
    } else {
      colors = this._custom;
    }
    let index = colors.indexOf(color);
    index--;
    if (index < 0) index = 0;
    return colors[index];
  },
  /**
   * èŽ·å–ç›‘æµ‹å› å­å½“å‰æµ“åº¦å¯¹åº”çš„é¢œè‰²
   * @param name ç›‘测因子名称
   * @param data ç›‘测因子浓度
   */
  getStandardColor: function (name, data) {
    var range = this._legend_r[name];
    var colors = this._legend_c[name];
    let range = this._legend_r[name];
    let colors = this._legend_c[name];
    if (range == undefined) {
      range = this._legend_r['PM25'];
      colors = this._legend_c['PM25'];
    }
    // return colors[0]
    var selected = undefined;
    let selected = undefined;
    for (let i = 0; i < range.length; i++) {
      const d = range[i];
      var d1 = d;
      let d1 = d;
      if (name == 'CO') {
        d1 *= 1000;
      }
src/stores/device.js
@@ -3,10 +3,18 @@
import deviceApi from '@/api/deviceApi';
import { useFetchData } from '@/composables/fetchData';
// èµ°èˆªä»»åŠ¡
// èµ°èˆªè®¾å¤‡
export const useDeviceStore = defineStore('device', () => {
  const deviceList = ref([]);
  const { loading, fetchData } = useFetchData();
  function getDevice(deviceType) {
    if (deviceType) {
      return deviceList.value.filter((v) => v.deviceType == deviceType);
    } else {
      return deviceList.value;
    }
  }
  function fetchDevice(type) {
    return fetchData((page, pageSize) => {
@@ -38,5 +46,5 @@
    });
  }
  return { deviceList, loading, fetchDevice, deleteDevice };
  return { deviceList, loading, getDevice, fetchDevice, deleteDevice };
});
src/stores/scene.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,32 @@
import { ref } from 'vue';
import { defineStore } from 'pinia';
import { useFetchData } from '@/composables/fetchData';
import sceneInfoApi from '@/api/sceneInfoApi';
import { useToolboxStore } from '@/stores/toolbox';
const toolboxStore = useToolboxStore();
// èµ°èˆªè®¾å¤‡
export const useSceneStore = defineStore('scene', () => {
  // é»˜è®¤æœç´¢èŒƒå›´1公里以内
  const radius = ref(1);
  const sceneList = ref([]);
  const { loading, fetchData } = useFetchData();
  function searchScene(lng, lat) {
    if (toolboxStore.sceneSearchStatus) {
      return fetchData(() => {
        return sceneInfoApi
          .searchByCoordinate(lng, lat, radius.value * 1000)
          .then((res) => {
            sceneList.value = res.data.filter((v) => {
              return v.typeId != 19 && v.typeId != 20;
            });
            return res;
          });
      });
    }
  }
  return { radius, sceneList, loading, searchScene };
});
src/stores/toolbox.js
@@ -14,6 +14,8 @@
  const dataMarkerStatus = ref(true);
  // å¼€å…³æ•°æ®å¼¹æ¡†
  const dataDialogStatus = ref(true);
  // å¼€å…³æº¯æºæ¸…单
  const sceneSearchStatus = ref(true);
  return {
    featuresStatus,
@@ -21,6 +23,7 @@
    controlbarStatus,
    coorPickStatus,
    dataMarkerStatus,
    dataDialogStatus
    dataDialogStatus,
    sceneSearchStatus
  };
});
src/styles/elementUI.scss
@@ -12,17 +12,19 @@
.el-button-custom {
  --el-button-bg-color: var(--bg-color);
  --el-button-hover-text-color: var(--select_color);
  --el-button-hover-bg-color: var(--bg-color);
  --el-button-border-color: var(--font-color);
  // --el-button-hover-text-color: var(--select_color);
  // --el-button-hover-bg-color: var(--bg-color);
  --el-button-hover-bg-color: var(--select_color);
  --el-button-active-border-color: transparent;
}
.el-button-custom-light {
  --el-button-bg-color: var(--font-color);
  --el-button-text-color: var(--bg-color);
  --el-button-hover-text-color: var(--bg-color);
  --el-button-hover-bg-color: var(--font-color);
  // --el-button-hover-text-color: var(--bg-color);
  // --el-button-hover-bg-color: var(--font-color);
  --el-button-hover-bg-color: var(--select_color);
  --el-button-border-color: var(--bg-color);
  --el-button-active-border-color: transparent;
}
src/utils/chart/chart-option.js
@@ -22,16 +22,27 @@
    animationDelayUpdate: function (idx) {
      return idx * 5;
    },
    // toolbox: {
    toolbox: {
    //   bottom: 0,
    //   feature: {
      feature: {
    //     dataZoom: {},
    //     magicType: {
    //       type: ['line', 'bar']
    //     },
    //     restore: {}
    //   }
        // restore: {
        //   title: '刷新'
    // },
        saveAsImage: {
          show: true,
          backgroundColor: '#122b54a9',
          name: '走航监测图',
          title: '保存为图片',
          iconStyle: {
            borderColor: '#fff'
          }
        }
      }
    },
    tooltip: {
      textStyle: {
        fontSize: fontSize
src/utils/factor/data.js
@@ -159,24 +159,25 @@
/**
 * èŽ·å–åŽ†å²æ•°æ®
 */
function fetchHistoryData(params) {
  // if (import.meta.env.VITE_DATA_MODE == 'jingan') {
  //   const _params = {
  //     compUser: 'user1',
  //     compPassword: 'User1@jingan',
  //     mn: params.deviceCode,
  //     dtFrom: params.startTime
  //       ? params.startTime
  //       : moment().subtract(6, 'm').format('YYYY-MM-DD HH:mm:ss'),
  //     dtTo: params.endTime
  //       ? params.endTime
  //       : moment().format('YYYY-MM-DD HH:mm:ss')
  //   };
  //   return fetchThirdPartyData(_params);
  // } else {
  //   return fetchOriginHistoryData(params);
  // }
function fetchHistoryData(params, origin = true) {
  if (origin) {
  return fetchOriginHistoryData(params);
  } else if (import.meta.env.VITE_DATA_MODE == 'jingan') {
    const _params = {
      compUser: 'user1',
      compPassword: 'User1@jingan',
      mn: params.deviceCode,
      dtFrom: params.startTime
        ? params.startTime
        : moment().subtract(6, 'm').format('YYYY-MM-DD HH:mm:ss'),
      dtTo: params.endTime
        ? params.endTime
        : moment().format('YYYY-MM-DD HH:mm:ss')
    };
    return fetchThirdPartyData(_params);
  } else {
    return fetchOriginHistoryData(params);
  }
}
var fetchingTask;
src/utils/map/3dLayer.js
@@ -97,6 +97,7 @@
  const heights = factor.heights;
  const colors = factor.colors;
  const bColor = factor.bottomColor;
  const bColors = factor.bottomColors;
  // eslint-disable-next-line no-undef
  var cylinder = new AMap.Object3D.Mesh();
@@ -133,10 +134,8 @@
      }
    }
    // var bColor = bColor
    var tColor = colors[i];
    geometry.vertexColors.push.apply(geometry.vertexColors, bColor); //底部顶点颜色
    geometry.vertexColors.push.apply(geometry.vertexColors, tColor); //顶部顶点颜色
    geometry.vertexColors.push.apply(geometry.vertexColors, bColors[i]); //底部顶点颜色
    geometry.vertexColors.push.apply(geometry.vertexColors, colors[i]); //顶部顶点颜色
  }
  // 7.根据合并选项重置或新增当前缓存数据
src/utils/map/dialog.js
@@ -4,17 +4,14 @@
import { windDir } from '@/constant/wind-dir';
import { map } from './index_old';
import { checkboxOptions } from '@/constant/checkbox-options';
import { useToolboxStore } from '@/stores/toolbox';
const toolboxStore = useToolboxStore();
export const DialogUtil = {
  show: true,
  toggleDataDialog() {
    this.show = !this.show;
    if (this.show) {
      return '数据弹框:开';
    } else {
      return '数据弹框:关';
    }
  },
  // å½“前打开的弹框及位置坐标
  marker: undefined,
  lnglat: undefined,
  /**
   * åˆ›å»ºå¼¹å‡ºæ¡†
   * @param {*} factorDatas ç›‘测数据
@@ -39,7 +36,7 @@
      offset: new AMap.Pixel(16, -45),
      autoMove: false
    });
    return m.window;
    return m;
  },
  /**
@@ -243,15 +240,45 @@
    return info;
  },
  /**
   * å¼€å¯ä¸€ä¸ªæ–°çš„æ•°æ®å¼¹æ¡†
   * @param {String} deviceType è®¾å¤‡ç±»åž‹
   * @param {String} deviceCode è®¾å¤‡ç¼–号
   * @param {Array} factorDatas ç›‘测数据
   * @param {Number} i æ•°æ®ç´¢å¼•
   * @param {Function} onClose å¼¹æ¡†å…³é—­å›žè°ƒ
   * @returns
   */
  openNewWindow(deviceType, deviceCode, factorDatas, i, onClose) {
    if (!this.show) return;
    const window = this.createInfoWindow(
    if (!toolboxStore.dataDialogStatus) return;
    this.marker = this.createInfoWindow(
      deviceType,
      deviceCode,
      factorDatas,
      i,
      onClose
    );
    window.open(map, factorDatas.lnglats_GD[i]);
    this.marker.window.open(map, factorDatas.lnglats_GD[i]);
    this.lnglat = factorDatas.lnglats_GD[i];
  },
  /**
   * æ‰“开缓存中的弹框
   */
  openWindow() {
    if (this.marker && this.lnglat) {
      // this.marker.close();
      this.marker.window.open(map, this.lnglat);
    }
  },
  /**
   * å…³é—­å·²å¼¹å‡ºçš„弹框
   */
  closeWindow() {
    if (this.marker) {
      // this.marker.close();
      this.marker.window.close();
    }
  }
};
src/utils/map/marks.js
@@ -79,13 +79,20 @@
    }
  },
  createLabelMarks(img, dataList) {
  /**
   * åˆ›å»ºæ ‡è®°ç‚¹
   * @param {string | Array} img å›¾æ ‡æˆ–图标数组
   * @param {Array} dataList ç›‘测数据
   * @param {boolean} collision æ ‡æ³¨é¿è®©
   * @returns
   */
  createLabelMarks(img, dataList, collision = true) {
    // eslint-disable-next-line no-undef
    const layer = new AMap.LabelsLayer({
      zooms: [3, 20],
      zIndex: 1000,
      // å¼€å¯æ ‡æ³¨é¿è®©ï¼Œé»˜è®¤ä¸ºå¼€å¯ï¼Œv1.4.15 æ–°å¢žå±žæ€§
      collision: true,
      collision: collision,
      // å¼€å¯æ ‡æ³¨æ·¡å…¥åŠ¨ç”»ï¼Œé»˜è®¤ä¸ºå¼€å¯ï¼Œv1.4.15 æ–°å¢žå±žæ€§
      animation: true
    });
@@ -103,7 +110,7 @@
        zIndex: 10,
        icon: {
          type: 'image',
          image: img,
          image: typeof img === 'string' ? img : img[i],
          // clipOrigin: [14, 92],
          // clipSize: [50, 68],
          size: [30, 30],
src/utils/map/sector.js
@@ -241,6 +241,7 @@
      object3Dlayer.remove(_sector);
    }
  },
  sectorParams: sectorParams,
  /**
   * ç»˜åˆ¶æ‰‡å½¢
   * @param {FactorDatas} fDatas
src/utils/map/toolbox.js
@@ -1,7 +1,7 @@
/* eslint-disable no-undef */
import { map, satellite } from './index_old';
import { useToolboxStore } from '@/stores/toolbox';
// import '@/lib/jquery-3.5.1.min';
import { DialogUtil } from '@/utils/map/dialog';
const toolboxStore = useToolboxStore();
@@ -44,7 +44,9 @@
   * @param {boolean} value
   */
  toggleFeatures(value) {
    value ? map.setFeatures(['bg', 'road', 'point', 'building']) : map.setFeatures(['bg', 'road']);
    value
      ? map.setFeatures(['bg', 'road', 'point', 'building'])
      : map.setFeatures(['bg', 'road']);
    toolboxStore.featuresStatus = value;
  },
@@ -81,5 +83,24 @@
      _locationText = undefined;
    }
    toolboxStore.coorPickStatus = value;
  },
  /**
   * å¼€å…³æ•°æ®å¼¹æ¡†
   */
  toggleDataDialogStatus(value) {
    toolboxStore.dataDialogStatus = value;
    if (value) {
      DialogUtil.openWindow();
    } else {
      DialogUtil.closeWindow();
    }
  },
  /**
   * å¼€å…³æº¯æºæ¸…单
   */
  toggleSceneSearch(value) {
    toolboxStore.sceneSearchStatus = value;
  }
};
src/utils/map/util.js
@@ -62,14 +62,14 @@
};
export default {
  setCenter(lnglat) {
    if (isDragging) {
  setCenter(lnglat, ignore = false) {
    if (!ignore && isDragging) {
      return;
    }
    var now = new Date();
    if (
      this.lasttime == undefined ||
      now.getTime() - this.lasttime.getTime() >= 1000
      now.getTime() - this.lasttime.getTime() >= 200
    ) {
      map.setCenter(lnglat);
      this.lasttime = now;
src/views/HomePage.vue
@@ -4,8 +4,10 @@
    <CoreHeader></CoreHeader>
    <el-row class="dropdown-wrap">
      <MapToolbox></MapToolbox>
      <MissionManage></MissionManage>
      <!-- <MissionManage></MissionManage> -->
      <ConfigManage></ConfigManage>
      <!-- <MapLocation></MapLocation> -->
      <SceneSearch></SceneSearch>
      <MapScene></MapScene>
    </el-row>
    <CoreMenu></CoreMenu>
@@ -30,6 +32,7 @@
}
.dropdown-wrap {
  /* background-color: aliceblue; */
  position: absolute;
  top: 10px;
  left: 2px;
src/views/LoginPage.vue
@@ -42,13 +42,13 @@
</template>
<script>
import underwayPng from '@/assets/mipmap/underway-2.png';
import underwayPng2 from '@/assets/mipmap/underway-2.png';
import underwayPng from '@/assets/mipmap/underway.png';
import { ElMessage } from 'element-plus';
export default {
  data() {
    return {
      underwayPng: underwayPng,
      formObj: {},
      rules: {
        userName: [
@@ -68,6 +68,15 @@
      }
    };
  },
  computed: {
    underwayPng() {
      if (import.meta.env.VITE_DATA_MODE == 'jingan') {
        return underwayPng2;
      } else {
        return underwayPng;
      }
    }
  },
  methods: {
    login() {
      this.$refs.formRef.validate((valid) => {
src/views/historymode/HistoryMode copy.vue
ÎļþÒÑɾ³ý
src/views/historymode/HistoryMode.vue
@@ -5,7 +5,7 @@
        v-show="status == 0"
        :search-time="searchTime"
        :loading="loading"
        @search="fetchHistroyData"
        @search="onSearch"
      ></SearchBar>
      <TrajectoryState v-show="status != 0" :status="status"></TrajectoryState>
    </el-row>
@@ -62,10 +62,13 @@
import DataSheet from './component/DataSheet.vue';
import { ElMessage } from 'element-plus';
import { fetchHistoryData } from '@/utils/factor/data';
import { mapStores } from 'pinia';
import { useSceneStore } from '@/stores/scene';
export default {
  components: { TrendAnalysis, DataSheet },
  setup() {
    // é™å®šåˆ†é¡µæ•°æ®é‡ä¸º10000
    const { loading, fetchData } = useFetchData(10000);
    return { loading, fetchData };
  },
@@ -89,7 +92,9 @@
      // å½“前选中高亮的数据点索引
      locateIndex: undefined,
      // è½¨è¿¹åŠ¨ç”»çŠ¶æ€
      status: 0
      status: 0,
      // æ˜¯å¦é¡µé¢å·²è·³è½¬
      isUnmounted: false
    };
  },
  watch: {
@@ -98,6 +103,9 @@
        this.draw();
      }
    }
  },
  computed: {
    ...mapStores(useSceneStore)
  },
  methods: {
    // æ£€æŸ¥æ•°æ®ç»çº¬åº¦æ˜¯å¦åˆæ³•
@@ -118,7 +126,11 @@
    // ç›‘听折线图和表格的点击事件
    handelIndexChange(index) {
      if (this.checkDataIsValid(index)) {
        // ç»˜åˆ¶æº¯æºæ‰‡å½¢
        this.drawSector(index);
        // æŸ¥è¯¢èŒƒå›´å†…的监测站点
        const [lng, lat] = this.factorDatas.lnglats_GD[index];
        this.sceneStore.searchScene(lng, lat);
      }
    },
    draw() {
@@ -137,11 +149,7 @@
    },
    drawMassMarks(e) {
      marks.drawMassMarks(this.factorDatas, e, (index) => {
        // æŸ¥è¯¢èŒƒå›´å†…的监测站点
        // SceneUtil.searchByCoordinate(lnglat[0], lnglat[1], distance);
        if (this.checkDataIsValid(index)) {
          this.drawSector(index);
        }
        this.handelIndexChange(index);
      });
      // è°ƒæ•´åœ°å›¾è§†è§’
      mapUtil.setBound(this.factorDatas.lnglats_GD);
@@ -165,6 +173,7 @@
      );
    },
    onFetchData(deviceType, data) {
      if (this.isUnmounted) return;
      // todo æ ¹æ®è®¾å¤‡ç±»åž‹åˆ‡æ¢åœ°å›¾ç›‘测因子展示单选框、折线图复选框、数据表格复选框的因子类型
      this.deviceType = deviceType;
      this.factorDatas.setData(data, this.drawMode, () => {
@@ -172,7 +181,7 @@
        this.draw();
      });
    },
    fetchHistroyData(option) {
    onSearch(option) {
      const { deviceType, deviceCode, timeArray } = option;
      this.deviceType = deviceType;
      this.deviceCode = deviceCode;
@@ -192,32 +201,13 @@
        }).then((res) => this.onFetchData(deviceType, res.data));
      });
    }
    // fetchRealTimeData() {
    //   // fixme 2024.5.3 æ­¤å¤„初始获取的数据,参数应该由searchbar决定,后续修改
    //   this.fetchData((page) => {
    //     return fetchHistoryData({
    //       deviceCode: '0a0000000001',
    //       // type: TYPE0,
    //       page,
    //       perPage: 100
    //     }).then((res) => {
    //       if (res.data.length > 0) {
    //         const s = new Date(res.data[0].time.replace(' ', 'T'));
    //         const e = new Date(
    //           res.data[res.data.length - 1].time.replace(' ', 'T')
    //         );
    //         this.searchTime = [s, e];
    //       }
    //       this.onFetchData(TYPE0, res.data);
    //     });
    //   });
    // }
  },
  mounted() {
    // this.fetchRealTimeData();
    this.isUnmounted = false;
  },
  unmounted() {
    mapUtil.clearMap();
    this.isUnmounted = true;
  }
};
</script>
src/views/realtimemode/RealtimeMode copy.vue
ÎļþÒÑɾ³ý
src/views/realtimemode/RealtimeMode.vue
@@ -103,13 +103,16 @@
    },
    fetchRealTimeData() {
      this.fetchData((page) => {
        return fetchHistoryData({
        return fetchHistoryData(
          {
          deviceCode: this.deviceCode,
          // startTime: '2024-08-20 06:00:00',
          // endTime: '2024-08-20 06:02:00',
          page,
          perPage: 100
        }).then((res) => {
          },
          false
        ).then((res) => {
          this.onFetchData(res.data);
          this.onMapData(res.data);
          // if (res.data.length > 0) {
@@ -146,7 +149,7 @@
        this.notFirstFetch = true;
      }
      startIndex = startIndex < 0 ? 0 : startIndex;
      return new Promise((resolve, reject) => {
      return new Promise(() => {
        this.allFactorDatas.addData(dataList, this.drawMode, () => {
          realTimeMapAnimation.moveAnimation(
            this.allFactorDatas,