Newer
Older
smartwell_front / src / views / home / dashboard / deviceMonitor.vue
liyaguang on 9 May 43 KB 新需求修改*2
<!--
  Description: 设备监控
  Author: 李亚光
  Date: 2025-03-19
 -->

<script lang="ts" setup name="DeviceMonitor">
import type { TableColumn } from '@/components/NormalTable/table_interface'
import AMap from '@/components/map/index.vue'
import { toTreeList } from '@/utils/structure'
import { mapData } from './components/mapData'
import { getDeviceMonitorList, getAreaStatistics, getPointStatistics } from '@/api/home/dashboard/index'
import { uniqueMultiArray } from '@/utils/Array'
import { getIconStyle } from './ponitMapStyle'
import wellInfo from '@/views/home/well/components/detailInfoDialog.vue'
import stationInfo from '@/views/home/station/station/components/detailInfoDialog.vue'
import piepleInfo from '@/views/home/pipeline/components/detailInfoDialog.vue'
import hiddenInfo from '@/views/home/temporary/components/detailInfoDialog.vue'
import { ElMessage } from 'element-plus'
import { uniqueArray } from '@/utils/Array'
const { proxy } = getCurrentInstance() as any
// /dashboard/district
const pageHeight = ref(0) // 液面高度

// 计算液面高度
const calcHeight = () => {
  pageHeight.value = window.innerHeight - 60 - 50 - 150 - 10 - 6 - 48 - 10 - 15
}
// 当前展示标识  map/list
const currentShow = ref('map')
// 切换展示
const changeShow = () => {
  if (currentShow.value === 'map') {
    currentShow.value = 'list'
  }
  else {
    currentShow.value = 'map'
  }
}
onMounted(() => {
  calcHeight()
})

window.addEventListener('resize', calcHeight)

onBeforeUnmount(() => {
  window.removeEventListener('resize', calcHeight)
})


// --------------------------列表操作-------------------------
const tableRef = ref()
// 监测对象数据列表
const monitorObjectList = ref<any[]>([])
const initMonitorObjectList = [
  { id: '1', value: '1', label: '闸井', pid: '0' },
  { id: '2', value: '2', label: '场站', pid: '0' },
  { id: '3', value: '3', label: '管线', pid: '0' },
  { id: '6', value: '-1,2,3', label: '隐患点', pid: '0' },
  { id: '7', value: '-1', label: '穿越缺陷点', pid: '6' },
  { id: '8', value: '-2', label: '占压隐患点', pid: '6' },
  { id: '9', value: '-3', label: '应急监测点', pid: '6' },
] as any[]
monitorObjectList.value = toTreeList(initMonitorObjectList)
const loadingTable = ref(false)
const tableData = ref<any[]>([])
const total = ref(0)
const columns = ref<TableColumn[]>([
  { text: '序号', value: 'index', align: 'center', width: '80' },
  { text: '位号', value: 'tagNumber', align: 'center', width: '100' },
  { text: '监测对象', value: 'watchObjectName', align: 'center', width: '100' },
  { text: '名称', value: 'ledgerName', align: 'center' },
  { text: '浓度', value: 'monitorValue', align: 'center', width: '130', isCustom: true, },
  { text: '外力破坏', value: 'force', align: 'center', width: '140' },
  { text: '地址', value: 'ledgerName', align: 'center', },
  { text: '管理单位', value: 'deptName', align: 'center', },
  { text: '电量', value: 'cell', align: 'center', width: '100' },
  { text: '监控状态', value: 'onlineStateName', align: 'center', width: '120', isCustom: true, },
  { text: '最新时间', value: 'logTime', align: 'center', width: '160' },
])
const tableRowClassName = ({ row }) => {
  // console.log(row, '111')
  if (row.onlineState === '2') {
    return 'alarm-row-device-monitor'
  }
  else {
    return ''
  }
}
// const columnsVirtual: Column<any>[] =
//   [
//     {
//       key: 'index',
//       title: '序号',
//       dataKey: 'index',
//       align: 'center',
//       width: 80,
//       // cellRenderer: ({ cellData: index }) => { index },
//     },
//     {
//       key: 'tagNumber',
//       title: '位号',
//       dataKey: 'tagNumber',
//       align: 'center',
//       width: 100,
//       // cellRenderer: ({ cellData: tagNumber }) => { tagNumber },
//     },
//     {
//       key: 'watchObjectName',
//       title: '监测对象',
//       dataKey: 'watchObjectName',
//       align: 'center',
//       width: 130,
//       // cellRenderer: ({ cellData: watchObjectName }) => { watchObjectName },
//     },
//     {
//       key: 'ledgerName',
//       title: '名称',
//       dataKey: 'ledgerName',
//       align: 'center',
//       // cellRenderer: ({ cellData: ledgerName }) => { ledgerName },
//     },
//     {
//       key: 'monitorValue',
//       title: '浓度',
//       dataKey: 'monitorValue',
//       align: 'center',
//       width: 130,
//       cellRenderer: ({ cellData: name }) => <ElTag>{name}</ElTag>
//     },
//     {
//       key: 'force',
//       title: '外力破坏',
//       dataKey: 'force',
//       align: 'center',
//       width: 140,
//       // cellRenderer: ({ cellData: force }) => { force },
//     },
//     {
//       key: 'ledgerName',
//       title: '地址',
//       dataKey: 'ledgerName',
//       align: 'center',
//       // cellRenderer: ({ cellData: ledgerName }) => { ledgerName },
//     },
//     {
//       key: 'deptName',
//       title: '管理单位',
//       dataKey: 'deptName',
//       align: 'center',
//       // cellRenderer: ({ cellData: deptName }) => { deptName },
//     },
//     {
//       key: 'cell',
//       title: '电量',
//       dataKey: 'cell',
//       align: 'center',
//       // cellRenderer: ({ cellData: cell }) => { cell },
//     },
//     {
//       key: 'onlineStateName',
//       title: '监控状态',
//       dataKey: 'onlineStateName',
//       align: 'center',
//       cellRenderer: ({ cellData: onlineStateName }) => { onlineStateName },
//     },
//     {
//       key: 'logTime',
//       title: '最新时间',
//       dataKey: 'logTime',
//       align: 'center',
//       // cellRenderer: ({ cellData: logTime }) => { logTime },
//     },

//   ]

// 列表查询条件
const listQuery = ref({
  offset: 1,
  limit: 20,
  watchType: '', // 风险类别 1:泄漏监测、2:防外力破坏、3:隐患监测
  watchObject: '', // 位置类型 1:闸井,2:场站,3:管线
  deptid: '',
  onlineState: '', // 监控状态(1:在线,0:离线,2:报警,3:故障)
})
// 重置查询条件
const reset = () => {
  listQuery.value = {
    offset: 1,
    limit: 20,
    watchType: '',
    watchObject: '',
    deptid: '',
    onlineState: '',
  }
  fetchData()
}
// 查询
const fetchData = (isScroll = false) => {
  const onlineStateDict = {
    1: '正常',
    2: '报警',
    3: '故障',
    0: '故障(离线)',
  } as { [key: string]: string }
  if (!isScroll) {
    loadingTable.value = true
    tableData.value = []
  }
  getDeviceMonitorList({
    ...listQuery.value,
    locationType: listQuery.value.watchObject.includes('-') ? listQuery.value.watchObject.split('-')[1] : '',
    watchObject: listQuery.value.watchObject.includes('-') ? '' : listQuery.value.watchObject
  }).then(res => {
    const data = res.data.rows.map((item: any, index: number) => ({
      ...item,
      onlineStateName: onlineStateDict[item.onlineState] || ' ',
      watchObjectName: initMonitorObjectList.filter(citem => citem.id === item.watchObject)[0]?.label || '',
      force: item.watchType === '2' && item.monitorContent ? item.monitorContent : '-',
    })).map((item: any) => ({
      ...item,
      onlineStateName: item.force !== '-' && item.onlineState === '2' && item.watchType === '2' ? `${item.onlineStateName}(${item.force.replace('报警', '')})` : item.onlineStateName
    }))
    if (!isScroll) {
      tableData.value = data.map((item: any, index: number) => ({ ...item, index: index + 1 }))
      // 设置表格到顶部
      tableRef.value.table.setScrollTop(0)

    }
    else {
      tableData.value = [...JSON.parse(JSON.stringify(tableData.value)), ...data]
      // 去重
      tableData.value = tableData.value.map((item: any, index: number) => ({
        ...item,
        index: index + 1,
      }))
    }
    total.value = res.data.total
    loadingTable.value = false
  }).catch(() => {
    loadingTable.value = false
  })
}
fetchData()
const searchData = () => {
  listQuery.value.offset = 1
  listQuery.value.limit = 20
  setTimeout(() => {
    fetchData()
  })
}
const loadmoreData = () => {
  listQuery.value.offset += 1
  setTimeout(() => {
    fetchData(true)
  })
}
// 页数发生变化后的操作,可能是页码变化,可能是每页容量变化,此函数必写
const changePage = (val: { size: number; page: number }) => {
  if (val && val.size) {
    listQuery.value.limit = val.size
  }
  if (val && val.page) {
    listQuery.value.offset = val.page
  }
  fetchData()
}

// 根据位号跳转
// const $router = useRouter()
// const toWatchObj = (row: any) => {
//   console.log(row, 'row')
//   if (row.locationType) {
//     //  隐患监测
//     $router.push({
//       name: 'TemporaryMonitorDetail',
//       query: {
//         id: row.id,
//         deviceCode: row.devcode,
//         typeName: row.typeName,
//       },
//     })
//   }
//   else {
//     if (row.watchObject === '1') {
//       // 闸井
//       $router.push({
//         path: `/well/detail`,
//         query: {
//           id: row.id,
//           row: JSON.stringify(row),
//         },
//       })
//     }
//     else if(row.watchObject === '2') {
//       //  场站
//     }
//   }
// }
// ---------------------地图------------------
const mapRef = ref()
const showMap = ref('')  // district  point
if (proxy.hasPerm('/dashboard/district')) {
  showMap.value = 'district'
}
else {
  showMap.value = 'point'
}
// 当前展示的行政区
const currentDistrict = ref('')
const loadingDistrict = ref(false)
// 是否展开表格
const expandDistrict = ref(true)
// 行政区信息统计数据
const districtColumns = ref<TableColumn[]>([
  { text: currentDistrict.value, value: 'name', align: 'center', width: 131 },
  { text: '正常', value: 'normal', align: 'center', width: 67 },
  { text: '报警', value: 'alarm', align: 'center', width: 67 },
  { text: '故障', value: 'exception', align: 'center', width: 67 },
  { text: '合计', value: 'total', align: 'center', width: 67 },
])
// 切换展开表格状态
const changeExpandDistrict = () => {
  expandDistrict.value = !expandDistrict.value
  if (expandDistrict.value) {
    districtColumns.value = [
      { text: currentDistrict.value, value: 'name', align: 'center', width: 131 },
      { text: '正常', value: 'normal', align: 'center', width: 67 },
      { text: '报警', value: 'alarm', align: 'center', width: 67 },
      { text: '故障', value: 'exception', align: 'center', width: 67 },
      { text: '合计', value: 'total', align: 'center', width: 67 },
    ]
  }
  else {
    districtColumns.value = [
      { text: currentDistrict.value, value: 'name', align: 'center', width: 131 },
      { text: '合计', value: 'total', align: 'center', width: 67 },
    ]
  }
}
// 表格表头样式
const tableHeaderStyle = (data: any) => {
  if (data.column.label === '正常') {
    return { color: '#00B011' }
  }
  else if (data.column.label === '报警') {
    return { color: '#f56c6c' }
  }
  else if (data.column.label === '故障') {
    return { color: '#FFBA00' }
  }
  else {
    return { color: '#000000' }
  }
}
const districtData = ref<any[]>([])
const districtDataLoading = ref(false)

// 点击行政区或者行政区名称
const clickDistrict = (receiveData: any) => {
  if (receiveData.style.name) {
    // console.log(receiveData)
    const showName = `${receiveData.style.name}(${areaData.value.filter(item => item.name.includes(receiveData.style.name) || receiveData.style.name.includes(item.name))[0]?.total || '0'})`
    currentDistrict.value = showName
    districtColumns.value[0].text = showName
    // 整理表格数据
    const list = areaData.value.filter(item => item.name.includes(receiveData.style.name) || receiveData.style.name.includes(item.name))
    let data = [
      { name: '泄漏监测', key: 'leak', normal: '0', alarm: '0', exception: '0', total: '0', off: '0', id: '1', pid: '0' },
      { name: '防外力破坏监测', key: 'damage', normal: '0', alarm: '0', exception: '0', off: '0', total: '0', id: '2', pid: '0' },
      { name: '隐患监测', key: 'hazard', value: '4', normal: '0', alarm: '0', exception: '0', off: '0', total: '0', id: '3', pid: '0', },
      { name: '穿越隐患点', key: 'hazard', value: '1', normal: '0', alarm: '0', exception: '0', off: '0', total: '0', id: '4', pid: '3' },
      { name: '占压隐患点', key: 'hazard', value: '2', normal: '0', alarm: '0', exception: '0', off: '0', total: '0', id: '5', pid: '3' },
      { name: '应急监测点', key: 'hazard', value: '3', normal: '0', alarm: '0', exception: '0', off: '0', total: '0', id: '6', pid: '3' },
    ] as any[]
    if (list.length) {
      const resultObj = list[0]
      data.forEach((item: any) => {
        // console.log(item, '111')
        for (const i in resultObj) {
          for (const y in item) {
            if (item.value && item.value !== '4') {
              // 穿越隐患点  占压隐患点 应急监测点
              if (i.toLocaleLowerCase().includes(item.key) && i.toLocaleLowerCase().includes(item.value) && i.toLocaleLowerCase().includes(y)) {
                item[y] = resultObj[i]
              }
            }
            else if (item.value && item.value === '4') {
              // 隐患监测
            }
            else {
              if (i.toLocaleLowerCase().includes(item.key) && i.toLocaleLowerCase().includes(y)) {
                item[y] = resultObj[i]
              }
            }
          }
        }
      })
      // 整理隐患监测数据
      data[2].normal = data.filter((item: any) => item.key === 'hazard' && item.value !== '4').reduce((acc: any, cur: any) => { return Number(acc.normal || 0) + Number(cur.normal) })
      data[2].alarm = data.filter((item: any) => item.key === 'hazard' && item.value !== '4').reduce((acc: any, cur: any) => { return Number(acc.alarm || 0) + Number(cur.alarm) })
      data[2].exception = data.filter((item: any) => item.key === 'hazard' && item.value !== '4').reduce((acc: any, cur: any) => { return Number(acc.exception || 0) + Number(cur.exception) })
      data[2].off = data.filter((item: any) => item.key === 'hazard' && item.value !== '4').reduce((acc: any, cur: any) => { return Number(acc.off || 0) + Number(cur.off) })
      data.forEach((item) => {
        item.exception = Number(item.exception) + Number(item.off)
      })
    }
    // 把数据整理成树
    districtData.value = toTreeList(data)
    // 展开表格
    if (!expandDistrict.value) {
      changeExpandDistrict()
    }
  }
}
// 双击行政区
const polygonDbClick = (data: any) => {
  return
  const areaCode = JSON.parse(localStorage.getItem('areaCode') as string)
  let result = []
  for (const i in areaCode) {
    result.push({
      name: `${areaCode[i]}区`,
      code: i
    })
  }
  console.log(result, mapData)
  const mapCodeData = mapData.map((item: any) => ({
    ...item,
    areaCode: result.filter((citem: any) => citem.name === item.name)[0].code
  }))

  const current = mapCodeData.filter(item => item.name.includes(data.style.name) || data.style.name.includes(item.name))[0]
  // 点位视图数据

  if (pointAllData.value.length) {
    // 设置中心点
    mapRef.value.map.setCenter(current.center)
    // 设置层级
    mapRef.value.map.setZoom(13)
    // current.areaCode
    // 挑选点位数据
    console.log(pointAllData.value, 'pointAllData')
    const pointData = pointAllData.value.filter((item: any) => item.row.area === current.areaCode)
    console.log(pointData, 'pointData')
    mapRef.value.addMassMarks({
      path: pointData,
      zIndex: 111,
      zooms: [3, 20],
      style: getIconStyle(),
      size: 20
    })
  }
  else {
    if (loadingPonit.value) {
      ElMessage.warning('点位数据加载中...')
    }
    else {
      ElMessage.warning('暂无数据')
    }
  }
}
// 获取行政区视图数据
const areaData = ref<any[]>([])
const handlerAreaData = (data: any[]) => {
  data.forEach((item: any, index: number) => {
    // 计算合计
    let total = 0
    const totalArr = []
    for (const i in item) {
      if (i.toLocaleLowerCase().includes('total')) {
        totalArr.push(Number(item[i]))
      }
    }
    total = totalArr.reduce((pre, next) => pre + next)
    areaData.value[index].total = total
    const json = mapData.filter((citem: any) => citem.name.includes(item.name))
    if (json.length) {
      // 绘制行政区
      mapRef.value.addPolygon(json[0].data, {
        name: `${item.name}区`,
        fillColor: '#0D76D4', // //多边形填充颜色
        strokeOpacity: 1, // 多边形填充透明度
        fillOpacity: 0.3, // 多边形填充透明度
        strokeColor: '#2b8cbe', // 线条颜色
        strokeWeight: 2, // 轮廓线宽度
        strokeStyle: 'dashed',
        strokeDasharray: [5, 5],
        activeFillColor: '#0D76D4', // 鼠标进入多边形的激活颜色
        dbclickSetCenter: false, // 双击多边形自动放大切切换中心试图
        dbclickCenter: [], // 中心坐标
        needHover: true,
      })
      // 添加标题
      mapRef.value.addText({
        text: `${item.name}区(${total})`,
        position: json[0].center,
        zIndex: 0,
      }, {
        'font-size': '18px',
        'color': '#000',
        'background-color': '#fff',
        'border-color': '#fff',
        'name': `${item.name}区`
      })
    }
  })
}
const fetchAreaData = () => {
  loadingDistrict.value = true
  getAreaStatistics().then(res => {
    // 处理数据
    const areaCode = JSON.parse(localStorage.getItem('areaCode') as string)
    let data = res.data
    let result = []
    for (const i in data) {
      data[i].name = areaCode[i]
      result.push(data[i])
    }
    // 过滤掉全是0的数据
    result = result.filter((item: any) => {
      const data = []
      for (const i in item) {
        if (i !== 'name') {
          data.push(Number(item[i]))
        }
      }
      return !data.every(citem => citem === 0)
    })
    areaData.value = result
    if (showMap.value === 'district') {
      handlerAreaData(areaData.value)
    }
    loadingDistrict.value = false

  }).catch(() => {
    loadingDistrict.value = false
  })
}

// 点位信息 图例操作
const loadingPonit = ref(false)
const defaultProps = {
  children: 'children',
  label: 'label',
}
const clusterOptions = {
  clusterOptions: 100,
  setMinClusterSize: 40
}
// 点位数据
const pointData = ref([])
const pointAllData = ref([])
// 树形选择数据
const pointTreeData = ref()
const selectTree = ref<string[]>([])
const treeRef = ref()
setTimeout(() => {
  const data = [
    { id: '1', value: '1-1', label: '泄漏监测', pid: '0' },
    { id: '2', value: '1', label: '闸井', pid: '1' },
    { id: '3', value: '2', label: '场站', pid: '1' },
    { id: '4', value: '3', label: '管线', pid: '1' },
    { id: '5', value: '5', label: '防外力破坏监测', pid: '0' },
    { id: '6', value: '2-1', label: '隐患监测', pid: '0' },
    { id: '7', value: '7', label: '穿越缺陷点', pid: '6' },
    { id: '8', value: '8', label: '占压隐患点', pid: '6' },
    { id: '9', value: '9', label: '应急监测点', pid: '6' },
  ] as any[]
  pointTreeData.value = toTreeList(data)
}, 1000);
// 获取点位数据
const fetchPonitData = () => {
  loadingPonit.value = true
  getPointStatistics().then(res => {
    const areaCode = JSON.parse(localStorage.getItem('areaCode') as string)
    let data = res.data.filter((item: any) => item.latGaode && item.lngGaode && item.id).map((item: any) => ({
      ...item,
      areaName: areaCode[item.area]
    }))
    // 处理 watchType为多个的情况
    const multipleAttribute = ref<any[]>([])
    data.forEach((item: any) => {
      if (item.watchType.includes(',')) {
        multipleAttribute.value.push(item)
      }
    })
    data = data.filter((item: any) => !item.watchType.includes(','))
    if (multipleAttribute.value.length) {
      multipleAttribute.value.forEach((item: any) => {
        data.push({ ...item, watchType: item.watchType.split(',')[0] })
        data.push({ ...item, watchType: item.watchType.split(',')[1] })
      })
    }
    // 分类整理数据
    data.forEach((element: any) => {
      if (!element.value) {
        if (element.watchType === '1') {
          // 泄漏监测
          element.value = element.type
        }
        if (element.watchType === '2') {
          element.value = '5'
        }
        if (element.monitorType === '0' && element.locationType && element.locationType !== '0') {
          const dict = {
            1: '7',
            2: '8',
            3: '9'
          } as { [key: string]: string }
          if (!element.value) {
            element.value = dict[element.locationType]
          }
          else {
            data.push({
              ...element,
              value: dict[element.locationType]
            })
          }
        }
      }

    })
    // (1:正常,2:异常,3:故障)
    // 1 闸井 2 场站 3 管线  5 外力破坏 7 穿越缺陷点 8 占压隐患点 9 应急监测点
    const style = getIconStyle().map((item: any) => ({
      ...item,
      // anchor: new mapRef.value.AMap.Pixel(4, 4),
      // size: new mapRef.value.AMap.Size(20, 20),
    }))
    const styleDict = {
      '1-1': 0, // 闸井-正常
      '1-2': 1, // 闸井-异常
      '1-3': 2, // 闸井-故障

      '2-1': 3, // 场站-正常
      '2-2': 4, // 场站-异常
      '2-3': 5, // 场站-故障

      '3-1': 6, // 管线-正常
      '3-2': 7, // 管线-异常
      '3-3': 8, // 管线-故障

      '5-1': 9, // 外力破坏-正常
      '5-2': 10, // 外力破坏-异常
      '5-3': 11, // 外力破坏-故障

      '7-1': 12, // 穿越缺陷点-正常
      '7-2': 13, // 穿越缺陷点-异常'
      '7-3': 14, // 穿越缺陷点-故障'

      '8-1': 15, // 占压隐患点-正常
      '8-2': 16, // 占压隐患点-异常'
      '8-3': 17, // 占压隐患点-故障'

      '9-1': 18, // 应急监测点-正常
      '9-2': 19, // 应急监测点-异常'
      '9-3': 20 // 应急监测点-故障'
    } as { [key: string]: number }
    pointData.value = data.filter((item: { value: string, onlineState: string }) => item.value && item.onlineState).map((item: any) => ({
      ...item,
      onlineState: item.onlineState === '0' ? '3' : item.onlineState
    })).map((item: any) => ({
      lnglat: [item.lngGaode, item.latGaode],
      // name: item.ledgerName,
      id: item.id,
      onlineState: item.onlineState,
      row: item,
      style: styleDict[`${item.value}-${item.onlineState}`],
      value: item.value
    }))
    //
    pointAllData.value = JSON.parse(JSON.stringify(pointData.value))
    if (showMap.value === 'point') {

      if (pointData.value.length > 400) {
        // if (selectTree.value.includes('1') || selectTree.value.includes('2') || selectTree.value.includes('3')) {
        // mapRef.value.addCluster(pointData.value, style, clusterOptions)

        // 数据根据value分类
        const allValue = uniqueArray(pointData.value.map((item: any) => item.value))
        allValue.forEach((item: any) => {
          const data = pointData.value.filter((i: any) => i.value === item)
          mapRef.value.addCluster(data, style, clusterOptions)
        })
      }
      else {
        mapRef.value.addMassMarks({
          path: pointData.value,
          zIndex: 111,
          zooms: [3, 20],
          style: style,
          size: 20
        })
      }
    }

    // 绘制点位聚合
    loadingPonit.value = false
  }).catch(() => {
    loadingPonit.value = false
  })
}
// 展示图例数据
const publicPath = window.location.href.split('#')[0]
const legendShowData = ref(['1', '2', '3'])
// 地图图例数据
const legendData = ref([
  {
    name: '正常',
    url: `${publicPath}/image/legend/normal.png`,
    value: '1',
  },
  {
    name: '报警',
    url: `${publicPath}/image/legend/alarm.png`,
    value: '2',
  },
  {
    name: '故障',
    url: `${publicPath}/image/legend/fault.png`,
    value: '3',
  },
])
const resetDraw = (type: 'status' | 'tree') => {
  if (!mapRef.value.map) { return }
  // 清除之前的图标展示
  mapRef.value.removeCluster()
  mapRef.value.removeMassMarks()
  const style = getIconStyle().map((item: any) => ({
    ...item,
    // anchor: new mapRef.value.AMap.Pixel(4, 4),
    // size: new mapRef.value.AMap.Size(20, 20),
  }))
  // 根据操作的不同图例操作
  if (type === 'status') {
    // drawMarker()
    pointData.value = pointAllData.value.filter((item: any) => legendShowData.value.includes(item.onlineState))
    const data = selectTree.value.filter((item: string) => !item.includes('-'))
    pointData.value = pointData.value.filter((item: any) => data.includes(item.value))
  } else {
    const data = selectTree.value.filter((item: string) => !item.includes('-'))
    console.log(data, '树形选择')

    pointData.value = pointAllData.value.filter((item: any) => legendShowData.value.includes(item.onlineState))
    pointData.value = pointData.value.filter((item: any) => data.includes(item.value))
  }
  if (pointData.value.length > 400) {
    // mapRef.value.addCluster(pointData.value, style, clusterOptions)
    const allValue = uniqueArray(pointData.value.map((item: any) => item.value))
        allValue.forEach((item: any) => {
          const data = pointData.value.filter((i: any) => i.value === item)
          mapRef.value.addCluster(data, style, clusterOptions)
        })
  }
  else {
    mapRef.value.addMassMarks({
      path: pointData.value,
      zIndex: 111,
      zooms: [3, 20],
      style: style,
      size: 20
    })
  }
}
const clickLegend = (type: string) => {
  if (legendShowData.value.includes(type)) {
    legendShowData.value = legendShowData.value.filter((item: string) => item !== type)
  }
  else {
    legendShowData.value.push(type)
  }
  resetDraw('status')
}
// 树形图例
const checkTreeChange = () => {
  const currentChecked = treeRef.value.getCheckedNodes().map((item: any) => item.value)
  selectTree.value = currentChecked
  setTimeout(() => {
    resetDraw('tree')
  })
}
// 展示更多图例
const showMoreLegend = ref(false)
const moreLegendData = ref([
  {
    name: '闸井',
    url: `${publicPath}/image/well/well-normal.png`,
    value: '1',
  },
  {
    name: '场站',
    url: `${publicPath}/image/station/station-normal.png`,
    value: '2',
  },
  {
    name: '管线',
    url: `${publicPath}/image/pipeline/pieple-normal.png`,
    value: '2',
  },
  {
    name: '防外力破坏',
    url: `${publicPath}/image/force/force-normal.png`,
    value: '2',
  },
  {
    name: '穿越缺陷点',
    url: `${publicPath}/image/pass/pass-normal.png`,
    value: '2',
  },
  {
    name: '占压隐患点',
    url: `${publicPath}/image/occupy/occupy-normal.png`,
    value: '2',
  },
  {
    name: '应急监测点',
    url: `${publicPath}/image/emergency/emergency-normal.png`,
    value: '2',
  },
  {
    name: '',
    url: ``,
    value: '2',
  },
  {
    name: '',
    url: ``,
    value: '2',
  }
])
// 信息窗体实例
const wellRef = ref() // 闸井
const stationRef = ref() // 场站
const piepleRef = ref() // 管线
const hiddenRef = ref()
const detail = ref()
// 地图点位点击
const massMarksClick = (data: any) => {
  // data.type    marks海量  cluster聚合
  // console.log(data, '111')
  const refDict = {
    1: wellRef.value,
    2: stationRef.value,
    3: piepleRef.value,
    5: piepleRef.value,
    7: hiddenRef.value,
    8: hiddenRef.value,
    9: hiddenRef.value,
  } as { [key: string]: any }
  const info = refDict[data.type === 'cluster' ? data.data.value : data.event.data.value]
  if (!info) { return }
  mapRef.value.map.setZoom(10.5)
  // 定义弹窗
  detail.value = new mapRef.value.AMap.InfoWindow({
    closeWhenClickMap: true, // 是否在鼠标点击地图后关闭信息窗体
    autoMove: true, // 是否自动调整窗体到视野内
    isCustom: true, // 自定义信息窗体
    content: info.$el, // 窗体内容(vue组件)
    offset: new mapRef.value.AMap.Pixel(9, -5), // 偏移
  })
  // 打开信息窗口
  detail.value.open(data.map, data.event.data.lnglat)
  // 初始化信息窗口
  info.initDialog({
    overlay: data.event.target,
    infoWindow: detail.value,
    info: data.event.data,
    map: mapRef.value.map,
  })
  setTimeout(() => {
    // mapRef.value.map.setZoom(14)
    // mapRef.value.map.setFitView()
    // mapRef.value.map.setCenter(data.event.data.lnglat)
    const center = JSON.parse(JSON.stringify(data.event.data.lnglat))
    center[1] = Number(center[1]) + 0.0002
    mapRef.value.map.setCenter(center)
  })
}
// 地图加载完成
const completeMap = () => {
  console.log('地图加载完成')
  // if (showMap.value === 'district') {
  fetchAreaData()
  // }
  // else {
  // 点位视图
  fetchPonitData()
  // }

  // 给地图绑定缩放事件
  // mapRef.value.map.on('zoomend', () => {
  //   console.log(mapRef.value.map.getZoom(), '缩放级别')
  //   if (mapRef.value.map.getZoom() > 11.5 && pointAllData.value.length) {
  //     mapRef.value.removeMassMarks()
  //     console.log(pointAllData.value, 'pointAllData.value')
  //     // 获取地图视图边界
  //     const viewportBounds = mapRef.value.map.getBounds()
  //     const northEast = viewportBounds.getNorthEast() //  获取东北角坐标(右上)
  //     const southWest = viewportBounds.getSouthWest() // 获取西南角坐标(左下)
  //     //  四个点坐标 当前视图区域
  //     const points = [
  //       { lng: southWest.lng, lat: northEast.lat },
  //       { lng: northEast.lng, lat: northEast.lat },
  //       { lng: northEast.lng, lat: southWest.lat },
  //       { lng: southWest.lng, lat: southWest.lat }
  //     ]
  //     // 在pointAllData里面找出 位于坐标内的点位
  //     const pointData = pointAllData.value.filter((item: any) => item.lnglat.length).filter((item: any) => {
  //        const lng =  Number(item.lnglat[0])
  //        const lat =  Number(item.lnglat[1])
  //       // 判断点位是否位于视图区域内
  //       return southWest.lng <= lng &&  lng <= northEast.lng  && northEast.lat >= lat && lat <= southWest.lat
  //     })
  //     console.log(pointData, 'pointData')
  //     // 绘制
  //     mapRef.value.addMassMarks({
  //         path: pointData,
  //         zIndex: 111,
  //         zooms: [3, 20],
  //         style: getIconStyle(),
  //       })
  //   }

  // })
}
watch(() => showMap.value, (newVal) => {
  if (!mapRef.value?.map || !newVal) { return }
  // 清除地图的绘制和标记
  mapRef.value.removePolygon()
  mapRef.value.removeText()
  mapRef.value.removeCluster()
  mapRef.value.removeMassMarks()
  currentDistrict.value = ''
  expandDistrict.value = true
  legendShowData.value = ['1', '2', '3']
  selectTree.value = ['1-1', '1', '2', '3', '5', '2-1', '7', '8', '9']
  if (detail.value) {
    // console.log('detail.value')
    detail.value?.close()
  }
  if (newVal === 'district') {
    if (areaData.value.length) {
      handlerAreaData(areaData.value)
    }
    else {
      if (loadingDistrict.value) { return }
      fetchAreaData()
    }
  }
  else if (newVal === 'point') {
    if (pointData.value.length) {
      // 如果点 大于200 聚合 否则不聚合
      if (pointAllData.value.length > 400) {
        // if (selectTree.value.includes('1') || selectTree.value.includes('2') || selectTree.value.includes('3')) {
        // mapRef.value.addCluster(pointAllData.value, getIconStyle().map((item: any) => ({
        //   ...item,
        //   // anchor: new mapRef.value.AMap.Pixel(4, 4),
        //   // size: new mapRef.value.AMap.Size(20, 20),
        // })), clusterOptions)
        const allValue = uniqueArray(pointAllData.value.map((item: any) => item.value))
        allValue.forEach((item: any) => {
          const data = pointAllData.value.filter((i: any) => i.value === item)
          mapRef.value.addCluster(data, getIconStyle(), clusterOptions)
        })
      }
      else {
        mapRef.value.addMassMarks({
          path: pointAllData.value,
          zIndex: 111,
          zooms: [3, 20],
          style: getIconStyle().map((item: any) => ({
            ...item,
            // anchor: new mapRef.value.AMap.Pixel(4, 4),
            // size: new mapRef.value.AMap.Size(20, 20),
          })),
          size: 20
        })
      }

    }
    else {
      if (loadingPonit.value) { return }
      fetchPonitData()
    }

  }
}, {
  deep: true,
  immediate: true,
})
</script>

<template>
  <el-card class="box-card">
    <template #header>
      <div class="card-header">
        <span>设备监控</span>
        <el-button type="primary" plain @click="changeShow">切换{{ currentShow === 'map' ? '列表' : '地图' }}模式</el-button>
      </div>
    </template>
    <div class="card-body" :style="{ height: `${pageHeight}px` }">
      <!-- 地图 -->
      <div class="map-container" v-show="currentShow === 'map'" :style="{ height: `${pageHeight}px` }">
        <!-- 地图切换按钮 -->
        <div class="change-map">
          <el-radio-group v-model="showMap">
            <el-radio-button v-if="proxy.hasPerm('/dashboard/district')" label="行政区视图" value="district" />
            <el-radio-button label="点位视图" value="point" />
          </el-radio-group>
        </div>
        <!-- 行政区信息 -->
        <div v-if="showMap === 'district' && currentDistrict" class="district-info"
          :style="{ width: `${expandDistrict ? '400' : '198'}px` }">
          <el-table ref="table" v-loading="districtDataLoading" :data="districtData" row-key="id" border stripe
            style="width: 100%;" :tree-props="{ children: 'children', hasChildren: 'hasChildren' }" size="small"
            :header-cell-style="tableHeaderStyle">
            <el-table-column v-for="column of districtColumns" :key="column.value" :label="column.text"
              :prop="column.value" :width="column.width" :align="column.align">
              <template v-if="column.value === 'name'" #header="scope">
                <span class="conatiner-header">
                  <el-icon v-if="expandDistrict" class="icon" @click="changeExpandDistrict">
                    <ArrowRightBold />
                  </el-icon>
                  <el-icon v-if="!expandDistrict" class="icon" @click="changeExpandDistrict">
                    <ArrowLeftBold />
                  </el-icon>
                  <span style="margin-left: 8px;">{{ column.text }}</span>
                </span>
              </template>
            </el-table-column>
          </el-table>
        </div>
        <!-- 点位视图信息 -->
        <div v-if="showMap === 'point'" class="point-info">
          <el-tree ref="treeRef" :data="pointTreeData" show-checkbox node-key="id" default-expand-all
            :default-checked-keys="[1, 2, 3, 4, 5, 6, 7, 8, 9]" :props="defaultProps" @check-change="checkTreeChange" />
        </div>
        <!-- 点位视图图例 -->
        <div v-if="showMap === 'point'" class="legend-info">
          <div v-for="item in legendData" :key="item.value" class="legend-item" @click="clickLegend(item.value)">
            <img v-show="legendShowData.includes(item.value)" class="img" :src="item.url">
            <img v-show="!legendShowData.includes(item.value)" class="img transparent" :src="item.url">
            <span style="margin-left: 5px;">{{ item.name }}</span>
          </div>
          <!-- 展开图标 -->
          <div v-if="!showMoreLegend" @click="showMoreLegend = true" class="expand-icon"><el-icon>
              <ArrowRightBold />
            </el-icon></div>
          <!-- 更多图标 -->
          <div v-if="showMoreLegend" class="more-legend-data">
            <div v-for="item in moreLegendData" :key="item.id" class="more-item">
              <img class="img" :src="item.url" v-show="item.url">
              <span style="margin-left: 5px;">{{ item.name }}</span>
            </div>
            <!-- 收起图标 -->
            <div v-if="showMoreLegend" @click="showMoreLegend = false" class="retract-icon"><el-icon>
                <ArrowLeftBold />
              </el-icon></div>
          </div>

        </div>
        <a-map v-loading="showMap === 'district' ? loadingDistrict : loadingPonit" ref="mapRef" :zoom="9"
          :center="[116.397428, 40.0331268311]" :show-pieple-layer="true" @complete="completeMap"
          @polygonClick="clickDistrict" @textClick="clickDistrict" @massMarksClick="massMarksClick"
          @polygonDbClick="polygonDbClick" />
      </div>

      <!-- 列表 -->
      <div class="list-container" v-show="currentShow === 'list'">
        <search-area :need-clear="true" @search="searchData" @clear="reset">
          <search-item>
            <el-select v-model="listQuery.watchType" placeholder="风险类别" filterable clearable class="select"
              style="width: 162px;">
              <el-option label="泄漏监测" value="1" />
              <el-option label="防外力破坏监测" value="2" />
              <el-option label="隐患监测" value="3" />
            </el-select>
          </search-item>
          <search-item>
            <!-- <el-select v-model="listQuery.watchObj" placeholder="监测对象" filterable clearable class="select"
              style="width: 162px;">
              <el-option v-for="item in []" :key="item.id" :label="item.name" :value="item.value" />
            </el-select> -->
            <el-tree-select v-model="listQuery.watchObject" :data="monitorObjectList" :render-after-expand="true"
              placeholder="监测对象" filterable clearable style="width: 162px;" check-strictly=true />
          </search-item>
          <search-item>
            <dept-select v-model="listQuery.deptid" placeholder="管理单位" :clearable="true" class="select"
              style="width: 162px;" />
          </search-item>
          <search-item>
            <el-select v-model="listQuery.onlineState" placeholder="监控状态" filterable clearable class="select"
              style="width: 162px;">
              <!-- <el-option v-for="item in []" :key="item.id" :label="item.name" :value="item.value" /> -->
              <el-option label="正常" value="1" />
              <el-option label="报警" value="2" />
              <el-option label="故障" value="0,3" />
            </el-select>
          </search-item>
        </search-area>
        <!-- <div :style="{ height: `${pageHeight}px` }">
          <el-auto-resizer>
            <template #default="{ height, width }">
              <el-table-v2 :columns="columnsVirtual" :data="tableData" :width="width" :height="height" />
            </template>
          </el-auto-resizer>
        </div> -->
        <normal-table ref="tableRef" v-tableAutoScroll="{ delay: 50, loadmore: loadmoreData }"
          v-loadmore="{ loadmore: loadmoreData }" :data="tableData" :total="total" :columns="columns" :query="listQuery"
          :list-loading="loadingTable" @change="changePage" :pagination="false" :height="pageHeight - 56 - 23"
          :tableRowClassName="tableRowClassName">
          <!-- <template #preColumns>
            <el-table-column label="序号" width="80" align="center">
              <template #default="scope">
                {{ (listQuery.offset - 1) * listQuery.limit + scope.$index + 1 }}
              </template>
            </el-table-column>
          </template> -->
          <template #isCustom="{ scope, column }">
            <!-- <span class="pointer link" v-if="column.text === '位号'" @click="toWatchObj(scope.row)">
              {{ scope.row[column.value] }}
            </span> -->
            <span v-if="column.text === '浓度'">
              <span class="normal" v-if="scope.row.onlineState === '1'">{{ scope.row.monitorValue ? scope.row.monitorValue : '-' }}</span>
              <span class="alarm" v-else>{{ scope.row.monitorValue ? scope.row.monitorValue : '-' }}</span>
              <!-- 单位 -->
              <span :class="scope.row.onlineState === '1' ? 'normal' : 'alarm'"
                v-if="scope.row.monitorValue && scope.row.monitorValue !== '0.00'">{{ scope.row.watchObjectName ===
                  '场站' ? 'PPM.M' : '%LEL' }}</span>
            </span>
            <span v-if="column.text === '监控状态'">
              <span class="normal" v-if="scope.row.onlineState === '1'">{{ scope.row.onlineStateName }}</span>
              <span class="alarm" v-else>{{ scope.row.onlineStateName }}</span>
            </span>
          </template>
        </normal-table>
      </div>
    </div>
    <!-- 设备信息窗体--闸井 -->
    <well-info ref="wellRef" />
    <!-- 设备信息窗体--场站 -->
    <station-info ref="stationRef" />
    <!-- 设备信息窗体--管线 -->
    <pieple-info ref="piepleRef" />
    <!-- 设备信息窗体--隐患 -->
    <hidden-info ref="hiddenRef" />
  </el-card>
</template>
<style lang="scss">
.alarm-row-device-monitor {
  background-color: rgba(248,220,220, 1) !important;

  // 消除striped颜色
  ::v-deep(.el-table__row--striped) {
    background-color: rgba(248,220,220, 1) !important;
  }

  td.el-table__cell {
    background-color: rgba(248,220,220, 1) !important;
  }

  &:hover>td {
    // 悬停颜色 上面的不用管
    background-color: rgba(248,220,220, 1) !important;
  }
}
</style>

<style lang="scss" scoped>
.pointer {
  &:hover {
    cursor: pointer;
  }
}

.link {
  color: #0d76d4 !important;

  &:hover {
    text-decoration: underline !important;
  }
}

::v-deep(.el-tree) {
  background: rgb(255 255 255 / 80%);
}

::v-deep(.el-card__body) {
  padding: 0;
}

::v-deep(.el-card__header) {
  padding: 0;
}

.alarm {
  color: red;
}

.box-card {
  margin-top: 10px;

  .card-header {
    font-weight: 700;
    color: #666;
    font-size: 18px;
    padding: 8px 16px;
    display: flex;
    justify-content: space-between;
    align-items: center;
  }

  .card-body {
    padding: 10px;
    position: relative;

    .map-container {
      position: relative;

      .change-map {
        position: absolute;
        top: 4px;
        left: 8px;
        z-index: 901;
      }

      .district-info {
        position: absolute;
        width: 400px;
        top: 38px;
        right: 8px;
        z-index: 9;
      }

      .point-info {
        position: absolute;
        width: 160px;
        top: 40px;
        left: 10px;
        z-index: 9;
      }

      .legend-info {
        position: absolute;
        bottom: 10px;
        left: 10px;
        z-index: 9;
        background: rgb(255 255 255 / 80%);
        padding: 0 10px;
        border-radius: 3px;
        width: 95px;
        height: 100px;

        .legend-item {
          margin: 10px 0;
          // font-weight: 700;
          display: flex;
          align-items: center;
          color: #000;

          .img {
            width: 20px;
            height: 20px;
          }

          .transparent {
            opacity: 0.25;
          }

          &:hover {
            cursor: pointer;
          }
        }

        .expand-icon {
          position: absolute;
          top: 50%;
          right: 0;
          transform: translateY(-50%);
          font-size: 20px;
          font-weight: 700;
          margin-top: 3px;

          &:hover {
            cursor: pointer;
            color: #0d76d4;
          }
        }

        .retract-icon {
          position: absolute;
          // transform: translateY(-50%);
          font-size: 20px;
          font-weight: 700;
          // margin-top: 3px;
          // top: 50%;
          right: -20px;
          // margin-top: 3px;
          background: rgb(255 255 255 / 80%);
          height: 100px;
          line-height: 100px;

          &:hover {
            cursor: pointer;
            color: #0d76d4;
          }
        }

        .more-legend-data {
          padding: 4px 0;
          display: flex;
          position: absolute;
          top: 0px;
          left: 80px;
          height: 100px;
          flex-wrap: wrap;
          flex-direction: column;
          justify-content: space-evenly;

          background: rgb(255 255 255 / 80%);
          width: 280px;

          .more-item {
            align-items: flex-start;
            // height: 33px;
            display: flex;
            align-items: center;
            color: #000;
            // margin: 10px 0;
            height: 30px;

            .img {
              width: 20px;
              height: 20px;
            }

            span {
              display: block;
              white-space: nowrap;
              margin-right: 5px;
            }

          }
        }
      }
    }
  }
}

.conatiner-header {
  display: flex;
  width: 100%;
  align-items: center;
  justify-content: center;

  .icon {
    &:hover {
      cursor: pointer;
      color: #0d76d4;
    }
  }
}
</style>