Newer
Older
smartwell_front / src / views / home / alarm / current / index.vue
liyaguang on 13 Dec 17 KB 需求修改
<!--
  Description: 报警管理-当前报警
  Author: 李亚光
  Date: 2023-06-28
 -->
<script lang="ts" setup name="CurrentAlarm">
import dayjs from 'dayjs'
import { ElLoading, ElMessage, ElMessageBox } from 'element-plus'
import { ArrowLeftBold, ArrowRightBold } from '@element-plus/icons-vue'
import MapCom from './components/map.vue'
import { batchDelete, detailAlarm, exportCurrentAlarm, getCurrentAlarmListPage } from '@/api/home/alarm/current'
import { getDictByCode } from '@/api/system/dict'
import { getAlarmLevelListPage, getAlarmTypeListPage } from '@/api/home/rule/alarm'
import { getDeviceTypeListPage } from '@/api/home/device/type'
import { uniqueMultiArray } from '@/utils/Array'
import { shortcuts } from '@/utils/common'
import { toHumpObject } from '@/utils/String'
import { exportFile } from '@/utils/exportUtils'
import { keepSearchParams } from '@/utils/keepQuery'
const alarmCategoryList = ref<{ id: string; name: string; value: string }[]>([]) // 报警类别
const alarmTypeList = ref<{ id: string; name: string; value: string }[]>([]) // 报警类型
const alarmLevelList = ref<{ id: string; name: string; value: string }[]>([]) // 报警等级
const deviceTypeList = ref<{ id: string; name: string; value: string }[]>([]) // 设备类型
const alarmStatusList = ref<{ id: string; name: string; value: string }[]>([]) // 报警状态
// 表格数据
const list1 = ref<any[]>([])
const total = ref(0)
const $route = useRoute()
const $router = useRouter()
// 初始展示列
const columns = ref<any>([
  { text: '报警类型', value: 'alarmType', align: 'center', width: '130' },
  { text: '报警等级', value: 'alarmLevelName', align: 'center', width: '85' },
  { text: '报警原因', value: 'alarmMsg', align: 'center' },
  { text: '位置', value: 'position', align: 'center' },
  { text: '设备类型', value: 'devTypeName', align: 'center', width: '145', isRequired: false, },
  { text: '设备编号', value: 'devcode', align: 'center', width: '160', isCustom: true, isRequired: false, },
  { text: '管理单位', value: 'deptName', align: 'center', width: '400' },
  { text: '状态', value: 'processStatusName', align: 'center', width: '120' },
  { text: '报警时间', value: 'alarmTime', align: 'center', width: '170' },
])
// 最终展示列
const columnsConfig = ref([])
// 修改列
const editColumns = (data: any) => {
  columnsConfig.value = data
}
const loadingTable = ref(true)
//  查询条件
const listQuery = ref({
  limit: 20,
  offset: 1,
  begTime: '',
  endTime: '',
  alarmCategory: '', // 报警类别
  alarmLevel: '', // 报警等级
  alarmTypeId: '', // 报警类型
  deptId: '', // 管理单位
  devCode: '', // 设备编号
  devTypeId: '', // 设备类型
  position: '', // 位置
  processStatus: '', // 报警状态
})
// 开始结束时间
const datetimerange = ref()
watch(() => datetimerange.value, (newVal) => {
  listQuery.value.begTime = ''
  listQuery.value.endTime = ''
  if (Array.isArray(newVal)) {
    if (newVal.length) {
      listQuery.value.begTime = `${newVal[0]}`
      listQuery.value.endTime = `${newVal[1]}`
    }
  }
})
// 查询数据
const fetchData = (isLoaidng = false) => {
  if ($route.query.row) {
    $router.push({
      path: '/alarm/current',
    })
  }
  loadingTable.value = true
  if (isLoaidng) {
    loadingTable.value = false
  }
  getCurrentAlarmListPage(listQuery.value).then((res) => {
    total.value = res.data.total
    list1.value = res.data.rows.map((item: any) => ({
      ...item,
      alarmCategoryName: alarmCategoryList.value.length ? alarmCategoryList.value.filter((citem: any) => citem.value === item.alarmCategory)[0]?.name : '',
    }))
    loadingTable.value = false
  }).catch(() => {
    loadingTable.value = false
  })
}
// 重置查询条件f
const reset = () => {
  if ($route.query.row) {
    $router.push({
      path: '/alarm/current',
    })
  }
  datetimerange.value = []
  listQuery.value = {
    limit: 20,
    offset: 1,
    begTime: '',
    endTime: '',
    alarmCategory: '', // 报警类别
    alarmLevel: '', // 报警等级
    alarmTypeId: '', // 报警类型
    deptId: '', // 管理单位
    devCode: '', // 设备编号
    devTypeId: '', // 设备类型
    position: '', // 位置
    processStatus: '', // 报警状态
  }
  fetchData()
}
// 页数发生变化后的操作,可能是页码变化,可能是每页容量变化,此函数必写
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()
}

onMounted(() => {
  if ($route.query.row) {
    loadingTable.value = true
    const row = JSON.parse($route.query.row as string)
    const obj = {
      begTime: '',
      endTime: '',
    }
    if ($route.query.real) {
      datetimerange.value = [dayjs().subtract(7, 'day').format('YYYY-MM-DD HH:mm:ss'), dayjs().format('YYYY-MM-DD HH:mm:ss')]
      obj.begTime = dayjs().subtract(7, 'day').format('YYYY-MM-DD HH:mm:ss')
      obj.endTime = dayjs().format('YYYY-MM-DD HH:mm:ss')
    }
    getCurrentAlarmListPage({ offset: 1, limit: 50, ...obj }).then((res) => {
      const data = res.data.rows.filter((item: any) => item.id === (row.id || row.alarmId))
      if (data.length) {
        list1.value = data.map((item: any) => ({
          ...item,
          alarmCategoryName: alarmCategoryList.value.length ? alarmCategoryList.value.filter((citem: any) => citem.value === item.alarmCategory)[0]?.name : '',
        }))
        setTimeout(() => {
          detail(data[0])
        })
      }
      else {
        list1.value = []
        ElMessage.warning('未找到该报警数据')
      }
      total.value = data.length
      loadingTable.value = false
    }).catch(() => {
      loadingTable.value = false
    })
    return
  }
  // datetimerange.value = [dayjs().subtract(7, 'day').format('YYYY-MM-DD HH:mm:ss'), dayjs().format('YYYY-MM-DD HH:mm:ss')]
  setTimeout(() => {
    fetchData()
  })
})
// 表格标识  地图或普通
const tableFlag = ref('normal')
const tableHeight = ref(0)
const switchMode = async (type: string) => {
  if (!list1.value.length) {
    ElMessage.warning('暂无数据')
    return
  }
  tableFlag.value = type
  // tableHeight.value = document.getElementById('container-table')?.clientHeight as number
  tableHeight.value = window.innerHeight - 60 - 50 - 98 - 20
}
watch(() => list1.value, () => {
  if (list1.value.length) {
    // tableHeight.value = document.getElementById('container-table')?.clientHeight as number
    tableHeight.value = window.innerHeight - 60 - 50 - 98 - 20
  }
})
window.addEventListener('resize', () => {
  // tableHeight.value = document.getElementById('container-table')?.clientHeight as number
  tableHeight.value = window.innerHeight - 60 - 50 - 98 - 20
  const ele = document.getElementById('dragItem-width')
  if (ele) {
    ele.style.height = `${tableHeight.value}px`
  }
})
// 查看报警
const mapRef = ref()
const mapData = ref({})
async function detail(row: any) {
  if (row.processStatusName === '未读') {
    list1.value[list1.value.findIndex((item: any) => item.id === row.id)].processStatusName = '已读'
    row.processStatusName = '已读'
  }
  const res = await detailAlarm(row.id)
  const data = toHumpObject(res.data)
  mapData.value = row
  switchMode('map')
  // 绘制点
  const draw = () => {
    mapRef.value.mapRef.removeMarker()
    mapRef.value.mapRef.addMarker({
      position: [data.lngGaode, data.latGaode],
      content: '<div class="spread-circle"></div>',
      label: '',
    })
    mapRef.value.mapRef.map.setFitView()
    mapRef.value.mapRef.map.setZoom(15)
    mapRef.value.openInfoDetail({
      ...row,
      lnglat: [data.lngGaode, data.latGaode],
    })
  }
  setTimeout(() => {
    if (!data.lngGaode || !data.latGaode) {
      ElMessage.warning('该数据缺少坐标信息')
      return
    }
    // 已读
    if (mapRef.value.completeFlag) {
      draw()
    }
    else {
      setTimeout(() => {
        draw()
      }, 1000)
    }
  })
}
// 字典
const fetchDict = () => {
  // 报警类别
  getDictByCode('alarmCategory').then((res) => {
    alarmCategoryList.value = res.data
  })
  // 报警类型
  getAlarmTypeListPage({ offset: 1, limit: 99999 }).then((res) => {
    alarmTypeList.value = uniqueMultiArray(res.data.rows.map((item: any) => ({
      name: item.alarmType,
      value: item.id,
      id: item.id,
    })), 'name')
  })
  // 报警等级
  getAlarmLevelListPage({ offset: 1, limit: 99999 }).then((res) => {
    alarmLevelList.value = res.data.rows.map((item: any) => ({
      name: item.alarmLevel,
      value: item.id,
      id: item.id,
    }))
  })
  // 设备类型
  getDeviceTypeListPage({ offset: 1, limit: 99999 }).then((res) => {
    deviceTypeList.value = res.data.rows.map((item: any) => ({
      name: item.typeName,
      value: item.id,
      id: item.id,
    }))
  })
  // 报警状态
  getDictByCode('alarmStatus').then((res) => {
    alarmStatusList.value = res.data
  })
}
fetchDict()
const { proxy } = getCurrentInstance() as any
// 多选
const multipleTable = ref([])
const handleSelectionChange = (val: any) => {
  console.log(val, '多选数据')
  multipleTable.value = val
}
// 导出列表
const exportList = () => {
  if (!list1.value.length) {
    ElMessage.warning('暂无导出数据')
    return
  }
  const loading = ElLoading.service({
    lock: true,
    background: 'rgba(255, 255, 255, 0.8)',
  })
  exportCurrentAlarm(listQuery.value).then((res) => {
    exportFile(res.data, '当前报警列表(数据).xlsx')
    loading.close()
  }).catch(() => {
    loading.close()
  })
}
// 批量删除
const batchDeleteRow = () => {
  if (!multipleTable.value.length) {
    ElMessage.warning('请先选中数据')
    return
  }
  ElMessageBox.confirm(
    '确定要处置选中的数据吗?',
    '确认操作',
    {
      confirmButtonText: '确定',
      cancelButtonText: '取消',
      type: 'warning',
    },
  ).then(() => {
    batchDelete(multipleTable.value.map((item: any) => item.id)).then(() => {
      ElMessage.success('操作成功')
      multipleTable.value = []
      fetchData()
    })
  })
}
// 跳转设备详情
const toDeviceDetail = (row: any) => {
  $router.push({
    name: 'DeviceManageDetail',
    params: {
      type: 'detail',
    },
    query: {
      row: JSON.stringify({
        devcode: row.devcode,
        deviceType: row.devTypeName,
        deviceTypeName: row.devTypeName,
        devTypeName: row.devTypeName,
      }),
    },
  })
}
onBeforeRouteLeave((to: any) => {
  keepSearchParams(to.path, 'CurrentAlarm')
})
onActivated(() => {
  // 从编辑或者新增页面回来需要重新获取列表数据
  // $router.options.history.state.forward 上一次路由地址
  if (!($router.options.history.state.forward as string || '').includes('detail')) {
    console.log('需要重新获取列表')
    fetchData()
  }
})
</script>

<template>
  <!-- 布局 -->
  <app-container>
    <!-- 筛选条件 -->
    <search-area :need-clear="true" @search="fetchData" @clear="reset">
      <search-item>
        <el-select v-model="listQuery.alarmCategory" placeholder="报警类别" clearable class="select" style="width: 192px;">
          <el-option v-for="item in alarmCategoryList" :key="item.id" :value="item.value" :label="item.name" />
        </el-select>
      </search-item>
      <search-item>
        <el-select v-model="listQuery.alarmTypeId" placeholder="报警类型" clearable class="select" style="width: 192px;">
          <el-option v-for="item in alarmTypeList" :key="item.id" :value="item.value" :label="item.name" />
        </el-select>
      </search-item>
      <search-item>
        <el-select v-model="listQuery.alarmLevel" placeholder="报警等级" clearable class="select" style="width: 192px;">
          <el-option v-for="item in alarmLevelList" :key="item.id" :value="item.value" :label="item.name" />
        </el-select>
      </search-item>
      <search-item>
        <el-select v-model="listQuery.devTypeId" placeholder="设备类型" clearable class="select" style="width: 192px;">
          <el-option v-for="item in deviceTypeList" :key="item.id" :value="item.value" :label="item.name" />
        </el-select>
      </search-item>
      <search-item>
        <el-select v-model="listQuery.processStatus" placeholder="报警状态" clearable class="select" style="width: 192px;">
          <el-option v-for="item in alarmStatusList" :key="item.id" :value="item.value" :label="item.name" />
        </el-select>
      </search-item>
      <search-item>
        <el-input v-model.trim="listQuery.position" placeholder="位置" clearable />
      </search-item>
      <search-item>
        <el-input v-model.trim="listQuery.devCode" placeholder="设备编号" clearable />
      </search-item>
      <search-item>
        <dept-select
          v-model="listQuery.deptId" placeholder="管理单位" :clearable="true" class="select"
          style="width: 192px;"
        />
      </search-item>
      <search-item>
        <el-date-picker
          v-model="datetimerange" type="datetimerange" format="YYYY-MM-DD HH:mm:ss" :shortcuts="shortcuts"
          value-format="YYYY-MM-DD HH:mm:ss" range-separator="至" start-placeholder="报警开始时间" end-placeholder="报警结束时间"
          clearable
        />
      </search-item>
    </search-area>
    <div style="width: 100%;display: flex;">
      <!-- 表头标题 -->
      <!-- v-drag-width="100" -->
      <div
        id="container-table" class="container-table"
        :style="{ width: `${tableFlag === 'normal' ? '100%' : '75%'}` }"
      >
        <table-container
          :is-config="true" config-title="current-alarm" :columns="columns"
          :config-columns="columnsConfig" :edit="editColumns"
        >
          <template #btns-right>
            <!-- 操作 -->
            <div>
              <el-button v-if="proxy.hasPerm('/alarm/current/delete')" type="primary" @click="batchDeleteRow">
                批量处置
              </el-button>
              <el-button v-if="proxy.hasPerm('/alarm/current/export')" type="primary" @click="exportList">
                导出
              </el-button>
            </div>
          </template>
          <!-- 查询结果Table显示 -->
          <normal-table
            :data="list1" :total="total" :columns="columnsConfig" :query="listQuery"
            :list-loading="loadingTable" :height="tableHeight - 50 - 70"
            :is-multi="proxy.hasPerm('/alarm/current/delete')"
            :is-showmulti-select="proxy.hasPerm('/alarm/current/delete')" @change="changePage"
            @multiSelect="handleSelectionChange"
          >
            <template #preColumns>
              <el-table-column label="序号" width="55" align="center">
                <template #default="scope">
                  {{ (listQuery.offset - 1) * listQuery.limit + scope.$index + 1 }}
                </template>
              </el-table-column>
            </template>
            <template #isCustom="{ scope, column }">
              <!-- 设备编号 -->
              <span
                v-if="column.text === '设备编号'" class="pointer link"
                @click="toDeviceDetail(scope.row)"
              >
                {{ scope.row[column.value] }}
              </span>
            </template>
            <template #columns>
              <el-table-column v-if="proxy.hasPerm('/alarm/current/detail')" label="操作" align="center" width="80">
                <template #default="scope">
                  <el-button type="primary" link size="small" @click="detail(scope.row)">
                    查看
                  </el-button>
                </template>
              </el-table-column>
            </template>
          </normal-table>
          <!-- 打开关闭地图模式 -->
          <div v-if="tableFlag !== 'normal'" id="mapMode" class="mapMode" :style="`height: ${tableHeight}px`">
            <!-- 打开 -->
            <div v-if="tableFlag === 'normal'" class="open" @click="switchMode('map')">
              <el-icon :size="30">
                <arrow-left-bold :size="30" />
              </el-icon>
            </div>
            <div v-if="tableFlag === 'map'" class="open" @click="switchMode('normal')">
              <el-icon :size="30">
                <arrow-right-bold :size="30" />
              </el-icon>
            </div>
          </div>
        </table-container>
      </div>
      <!-- 地图 -->
      <div v-if="tableFlag === 'map'" :style="`height: ${tableHeight}px`" class="map">
        <map-com ref="mapRef" :height="tableHeight - 10" :data="mapData" @refresh="fetchData(true)" />
      </div>
    </div>
  </app-container>
</template>

<style lang="scss">
.spread-circle {
  width: 25px;
  height: 25px;
  // background-color: #EE9611;
  border-radius: 50%;
  background: url("@/assets/images/spread.gif") no-repeat center center / cover;
}
</style>

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

.link {
  color: #0d76d4 !important;

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

.table {
  width: 100%;
}

.table-map {
  width: 75%;
}

.map {
  width: 25%;
  // background-color: antiquewhite;
}

.container-table {
  position: relative;

  .mapMode {
    // background-color: aqua;
    width: 1.5%;
    //  height: 100vh;
    position: absolute;
    right: -6px;
    top: 50%;
    z-index: 9;
    transform: translateY(-50%);

    &:hover {
      // cursor: col-resize;

      .open,
      .close {
        display: block;
      }
    }

    .open {
      position: absolute;
      top: 50%;
      transform: translateY(-50%);
      display: none;

      &:hover {
        cursor: pointer;
      }
    }
  }
}

.select {
  width: 100%;
}
</style>

<style>
.select {
  width: 192px !important;
}
</style>