index.vue 12.4 KB
<template>
  <div class="wrapper123">
    <div ref="wrapRef" :style="{ height, width }"> </div>
    <div class="right-wrap">
      <BasicTable @register="registerTable" @rowClick="deviceRowClick">
        <template #deviceState="{ record }">
          <Tag
            :color="
              record.deviceState == DeviceState.INACTIVE
                ? 'warning'
                : record.deviceState == DeviceState.ONLINE
                ? 'success'
                : 'error'
            "
            class="ml-2"
          >
            {{
              record.deviceState == DeviceState.INACTIVE
                ? '待激活'
                : record.deviceState == DeviceState.ONLINE
                ? '在线'
                : '离线'
            }}
          </Tag>
        </template>
      </BasicTable>
    </div>
    <BasicModal
      @register="registerModal"
      title="历史数据"
      width="70%"
      :footer="null"
      @cancel="cancelHistoryModal"
      :canFullscreen="false"
    >
      <BasicForm @register="registerForm" />
      <div ref="chartRef" :style="{ height: '400px', width }"></div>
    </BasicModal>
  </div>
</template>
<script lang="ts">
  import { defineComponent, ref, nextTick, unref, onMounted, Ref } from 'vue';
  import { useScript } from '/@/hooks/web/useScript';
  import { formSchema, columns } from './config.data';
  import { BasicTable, useTable } from '/@/components/Table';
  import { devicePage } from '/@/api/alarm/contact/alarmContact';
  import { Tag } from 'ant-design-vue';
  import { DeviceState } from '/@/api/device/model/deviceModel';
  import { BAI_DU_MAP_URL } from '/@/utils/fnUtils';
  import { useModal, BasicModal } from '/@/components/Modal';
  import { BasicForm, useForm } from '/@/components/Form';
  import { schemas } from './config.data';
  import { useECharts } from '/@/hooks/web/useECharts';
  import { getDeviceHistoryInfo } from '/@/api/alarm/position';
  import moment from 'moment';
  export default defineComponent({
    name: 'BaiduMap',
    components: {
      BasicTable,
      Tag,
      BasicModal,
      BasicForm,
    },
    props: {
      width: {
        type: String,
        default: '100%',
      },
      height: {
        type: String,
        default: 'calc(100vh - 78px)',
      },
    },
    setup() {
      const wrapRef = ref<HTMLDivElement | null>(null);
      const { toPromise } = useScript({ src: BAI_DU_MAP_URL });
      const entityId = ref('');
      async function initMap() {
        await toPromise();
        await nextTick();
        const wrapEl = unref(wrapRef);
        const BMap = (window as any).BMap;
        if (!wrapEl) return;
        const map = new BMap.Map(wrapEl);
        const point = new BMap.Point(104.04666605565338, 30.543516387560476);

        map.centerAndZoom(point, 15);
        map.enableScrollWheelZoom(true);
      }

      const [registerTable] = useTable({
        api: devicePage,
        columns,
        formConfig: {
          schemas: formSchema,
          labelAlign: 'left',
        },
        showIndexColumn: false,
        useSearchForm: true,
      });
      // 点击表格某一行触发
      const deviceRowClick = (record) => {
        entityId.value = record.tbDeviceId;
        const BMap = (window as any).BMap;
        const wrapEl = unref(wrapRef);
        const map = new BMap.Map(wrapEl);
        if (record.deviceInfo.address) {
          const { name, organizationDTO, updateTime, deviceState, deviceProfile } = record;
          const { longitude, latitude, address } = record.deviceInfo;
          const point = new BMap.Point(longitude, latitude);
          let options = {
            width: 300, // 信息窗口宽度
            height: 220, // 信息窗口高度
          };
          map.centerAndZoom(point, 15);
          map.enableScrollWheelZoom(true);
          // 创建信息窗口对象
          let infoWindow = new BMap.InfoWindow(
            `
            <div style="display:flex;justify-content:space-between; margin:20px 0px;">
              <div style="font-size:16px;font-weight:bold">${name}</div>
              ${
                deviceState === 'INACTIVE'
                  ? '<div style="display:flex;align-items:center"><img style="width:15px;height:15px" src="/src/assets/images/djh.png">待激活</div>'
                  : deviceState === 'ONLINE'
                  ? '<div style="display:flex;align-items:center"><img style="width:15px;height:15px" src="/src/assets/images/online1.png">在线</div>'
                  : '<div style="display:flex;align-items:center"><img style="width:15px;height:15px" src="/src/assets/images/lx1.png">离线</div>'
              }
            </div>
            <div>所属组织:${organizationDTO.name}</div>
            <div style="margin-top:6px;">接入协议:${deviceProfile.transportType}</div>
            <div style="margin-top:6px;">设备位置:${address}</div>
            <div style="margin-top:6px;">下线时间:${updateTime}</div>
            <div style="display:flex;justify-content:space-between; margin-top:10px">
              <button style="color:#fff;background-color:#409eff;padding:4px; border-radius:4px;">设备信息</button>
              <button style="color:#fff;background-color:#409eff;padding:4px; border-radius:4px;">报警记录</button>
              <button onclick="openHistoryModal()" style="color:#fff;background-color:#409eff;padding:4px; border-radius:4px;">历史数据</button>
            </div>
            `,
            options
          );

          map.openInfoWindow(infoWindow, map.getCenter());
          let preMarker = null;
          const rivet =
            deviceState === 'INACTIVE'
              ? '/src/assets/images/djx.png'
              : deviceState === 'ONLINE'
              ? '/src/assets/images/zx.png'
              : '/src/assets/images/lx.png';
          let myIcon = new BMap.Icon(rivet, new BMap.Size(20, 30));
          let marker = new BMap.Marker(point, { icon: myIcon });
          if (marker) {
            map.removeOverlay(preMarker);
          }
          map.addOverlay(marker);
        } else {
          const point = new BMap.Point(106.63028229687498, 36.06735821600903);
          let options = {
            width: 100, // 信息窗口宽度
            height: 100, // 信息窗口高度
            title: '提示', // 信息窗口标题
          };
          map.centerAndZoom(point, 5);
          map.enableScrollWheelZoom(true);
          let infoWindow = new BMap.InfoWindow('该设备暂无地理位置', options); // 创建信息窗口对象
          map.openInfoWindow(infoWindow, map.getCenter());
        }

        console.log(record);
      };

      const [registerModal, { openModal }] = useModal();
      const [registerForm, { resetFields, getFieldsValue, validate }] = useForm({
        labelWidth: 120,
        schemas,
        async submitFunc() {
          await validate();
          let { endTs, interval, agg } = getFieldsValue();
          if (!endTs) return;
          const startTs = Date.now() - endTs;
          endTs = Date.now();
          console.log(startTs, endTs);
          const res = await getDeviceHistoryInfo({
            entityId: entityId.value,
            keys: 'co,co2',
            interval,
            startTs,
            endTs,
            agg,
          });
          const dateArray: { key: string; time: string }[] = [];
          const valueArray: { key: string; value: string }[] = [];
          for (const key in res) {
            for (const item1 of res[key]) {
              let { ts, value } = item1;
              const time = moment(ts).format('YYYY-MM-DD');
              dateArray.push({
                key,
                time,
              });
              valueArray.push({
                key,
                value,
              });
            }
          }
          console.log(dateArray, valueArray);
          const keys = ['co', 'co2'];
          const series: any = keys.map((item) => {
            return {
              name: item,
              type: 'line',
              smooth: true,
              showAllSymbol: 'auto',
              symbol: 'emptyCircle',
              symbolSize: 15,
              data: valueArray.filter((item1) => item1.key === item).map((item1) => item1.value),
            };
          });
          setOptions({
            tooltip: {
              trigger: 'axis',
              axisPointer: {
                lineStyle: {
                  width: 1,
                  color: '#019680',
                },
              },
            },
            xAxis: {
              type: 'category',
              boundaryGap: false,
              data: dateArray.map((item) => item.time),
              splitLine: {
                show: true,
                lineStyle: {
                  width: 1,
                  type: 'solid',
                  color: 'rgba(226,226,226,0.5)',
                },
              },
              axisTick: {
                show: false,
              },
            },
            yAxis: [
              {
                type: 'value',
                max: 1000,
                splitNumber: 4,
                axisTick: {
                  show: false,
                },
                splitArea: {
                  show: true,
                  areaStyle: {
                    color: ['rgba(255,255,255,0.2)', 'rgba(226,226,226,0.2)'],
                  },
                },
              },
            ],
            grid: { left: '1%', right: '1%', top: '2  %', bottom: 0, containLabel: true },
            series,
          });
        },
      });

      const chartRef = ref<HTMLDivElement | null>(null);
      const { setOptions } = useECharts(chartRef as Ref<HTMLDivElement>);

      const openHistoryModal = async () => {
        const startTs = Date.now() - 86400000;
        const endTs = Date.now();
        console.log(startTs, endTs);
        const res = await getDeviceHistoryInfo({
          entityId: entityId.value,
          keys: 'co,co2',
          startTs,
          endTs,
        });
        const dateArray: { key: string; time: string }[] = [];
        const valueArray: { key: string; value: string }[] = [];
        for (const key in res) {
          for (const item1 of res[key]) {
            let { ts, value } = item1;
            const time = moment(ts).format('YYYY-MM-DD HH:mm:ss');
            dateArray.push({
              key,
              time,
            });
            valueArray.push({
              key,
              value,
            });
          }
        }

        const keys = ['co', 'co2'];
        const series: any = keys.map((item) => {
          return {
            smooth: true,
            data: valueArray.filter((item1) => item1.key === item).map((item1) => item1.value),
            type: 'line',
            name: item,
            itemStyle: {
              color: '#5ab1ef',
            },
          };
        });
        setOptions({
          tooltip: {
            trigger: 'axis',
            axisPointer: {
              lineStyle: {
                width: 1,
                color: '#019680',
              },
            },
          },
          xAxis: {
            type: 'category',
            boundaryGap: false,
            data: dateArray.map((item) => item.time),
            splitLine: {
              show: true,
              lineStyle: {
                width: 1,
                type: 'solid',
                color: 'rgba(226,226,226,0.5)',
              },
            },
            axisTick: {
              show: false,
            },
          },
          yAxis: {
            splitLine: { show: false },
            axisLine: {
              lineStyle: {
                color: '#ccc',
              },
            },
          },
          grid: { left: '1%', right: '1%', top: '2  %', bottom: 0, containLabel: true },
          series,
        });
        openModal(true);
      };
      const cancelHistoryModal = () => {
        resetFields();
      };
      onMounted(() => {
        initMap();
        (window as any).openHistoryModal = openHistoryModal;
      });
      return {
        wrapRef,
        registerTable,
        deviceRowClick,
        DeviceState,
        registerModal,
        registerForm,
        chartRef,
        cancelHistoryModal,
      };
    },
  });
</script>

<style scoped>
  .wrapper {
    position: relative;
  }
  .active {
    background-color: #fff;
  }
  .right-wrap {
    padding-top: 10px;
    width: 22%;
    height: 95%;
    position: absolute;
    right: 5%;
    top: 3%;
    background-color: #fff;
  }
</style>