Newer
Older
sensorHubPlusFront / src / views / basic / device / list.vue
liyaguang 8 days ago 13 KB 系统基础修改
<!-- 设备列表 -->
<script name="DeviceList" lang="ts" setup>
import { ElLoading, ElMessage, ElMessageBox, dayjs } from 'element-plus'
import type { IGroupInfo } from '../group/group-info'
import type { IDictType } from '../common-interface'
import type { IDeviceInfo, IListQuery } from './device-info'
import type { TableColumn } from '@/components/NormalTable/table_interface'
import { getDictByCode } from '@/api/system/dict'
import { exportFile } from '@/utils/exportUtils'
import { getGroupList } from '@/api/basic/group'
import { delDevice, exportDevice, getDeviceListPage, batchImportDevice } from '@/api/basic/device'
import { getDeviceLatestBizData } from '@/api/data/query'
import AddDeviceDialog from './addDeviceDialog.vue'
import batchconfig from './batchconfig.vue'
import axios from 'axios'

const router = useRouter()
const { proxy } = getCurrentInstance() as any
// 分组列表
const groupList = ref<Array<IGroupInfo>>([])

const cell = ref<string>('')
const cellLevelList = [
  { value: 1, name: '低于10%' },
  { value: 2, name: '低于20%' },
  { value: 3, name: '低于30%' },
  { value: 4, name: '低于50%' },
]

// 查询条件
const searchQuery = ref<IListQuery>({
  groupId: '', // 分组
  productId: '',
  devcode: '',
  imei: '',
  deviceType: '',
  status: '',
  offset: 1,
  limit: 20,
})
const total = ref(0) // 数据条数
const loadingTable = ref(false) // 表格loading

// 表头
const columns = ref<TableColumn[]>([
  { text: '状态', value: 'statusName', align: 'center', width: '80' },
  { text: '设备编号', value: 'devcode', align: 'center', width: '160' },
  { text: 'IMEI', value: 'imei', align: 'center', width: '160' },
  { text: '所属产品', value: 'productName', align: 'center', width: '160' },
  { text: '设备类型', value: 'deviceTypeName', align: 'center', width: '200' },
  { text: '设备型号', value: 'modelName', align: 'center', width: '200' },
  { text: '电量(%)', value: 'cell', align: 'center', width: '100' },
  { text: '最新数据', value: 'dataValue', align: 'center' },
  { text: '创建时间', value: 'createTime', align: 'center', width: '170' },
  { text: '最新上线时间', value: 'logtime', align: 'center', width: '170' },
])
const dataList = ref<Array<IDeviceInfo>>([]) // 表格数据

const statusDict = ref<Array<IDictType>>([])
const deviceTypeDict = ref<Array<IDictType>>([])

// 逻辑
// 导出所有
const exportAllDevice = () => {
  if (dataList.value.length > 0) {
    const filename = `设备列表${new Date().valueOf()}.xlsx`

    const loading = ElLoading.service({
      lock: true,
      text: '下载中请稍后',
      background: 'rgba(255, 255, 255, 0.8)',
    })

    // 导出接口
    exportDevice(searchQuery.value).then((res) => {
      const blob = new Blob([res.data])
      exportFile(blob, filename)

      nextTick(() => {
        // 关闭loading
        loading.close()
      })
    }).catch(() => {
      loading.close()
    })
  }
  else {
    ElMessage.warning('无数据可导出数据')
  }
}
// 模板下载
const downTemplate = () => {
  const loading = ElLoading.service({
    lock: true,
    background: 'rgba(255, 255, 255, 0.8)',
  })
  axios.get('./file/device_template.xlsx', {
    responseType: 'blob', // 关键配置
  }).then(res => {
    const blob = new Blob([res.data])
    loading.close()
    exportFile(blob, 'device_template.xlsx')
  }).catch(() => {
    loading.close()
  })
}
// 详情
const detail = (row: IDeviceInfo) => {
  router.push({
    query: {
      type: 'detail',
      id: row.id,
    },
    path: 'detail',
  })
}
// 上传逻辑
const fileRef = ref()
const onFileChange = (event: any) => {
  // 原生上传
  if (event.target.files?.length !== 0) {
    // 创建formdata对象
    const fd = new FormData()
    fd.append('file', event.target.files[0])
    const loading = ElLoading.service({
      lock: true,
      background: 'rgba(255, 255, 255, 0.8)',
    })
    batchImportDevice(fd).then((res) => {
      if (res.code === 200) {
        ElMessage.success('上传成功')
        loading.close()
        fileRef.value.value = ''
        fetchData(true)
      }
      else {
        // ElMessage.error(res.message)
        fileRef.value.value = ''
        loading.close()
      }
    }).catch(() => {
      // ElMessage.error(err.message)
      fileRef.value.value = ''
      loading.close()
    })
  }
}
// 导入文件批量新增
const batchAddDevice = () => {
  fileRef.value.click()
}
// 编辑
const updateById = (row: IDeviceInfo) => {
  sessionStorage.setItem('deviceInfo', JSON.stringify(row))
  refAddDeviceDialog.value.initDialog({ type: 'update', id: row.id })
}
// 数据查询
function fetchData(isNowPage = false) {
  loadingTable.value = true
  if (!isNowPage) {
    // 是否显示当前页,否则跳转第一页
    searchQuery.value.offset = 1
  }
  getDeviceListPage(searchQuery.value).then((response) => {
    if (response.code === 200) {
      dataList.value = response.data.rows.map((item: IDeviceInfo) => {
        return {
          ...item,
        }
      })
      total.value = parseInt(response.data.total)
    }
    calcTableHeight()
    loadingTable.value = false

    dataList.value.forEach((item) => {
      getDeviceLatestBizData({ devCode: item.devcode }).then((res) => {
        if (res.code === 200) {
          item.dataValue = res.data.value
          item.logtime = res.data.logtime
          item.cell = res.data.cell
        }
      })
    })
  }).catch(() => {
    loadingTable.value = false
  })
}

const searchList = () => {
  fetchData(true)
}

// 页数发生变化后的操作,可能是页码变化,可能是每页容量变化,此函数必写
const changePage = (val: { size?: number; page?: number }) => {
  if (val && val.size) {
    searchQuery.value.limit = val.size
  }
  if (val && val.page) {
    searchQuery.value.offset = val.page
  }
  fetchData(true)
}

// 重置
const reset = () => {
  cell.value = ''
  searchQuery.value = {
    groupId: '', // 分组
    productId: '',
    devcode: '',
    imei: '',
    deviceType: '',
    status: '',
    offset: 1,
    limit: 20,
  }
  fetchData(true)
}
// 批量下发配置
const batchConfigRef = ref()
const bacthConfig = () => {
  batchConfigRef.value.initDialog()
}
// 删除
const deleteDeviceById = (row: IDeviceInfo) => {
  ElMessageBox.confirm(`是否删除设备 ${row.devcode}`, '提示', {
    confirmButtonText: '确认',
    cancelButtonText: '取消',
    type: 'warning',
  }).then(() => {
    delDevice(row.id).then((res) => {
      if (res.code === 200) {
        ElMessage.success(`设备 ${row.devcode} 删除成功`)
        searchList()
      }
      else {
        ElMessage.error(`设备 ${row.devcode} 删除失败: ${res.message}`)
      }
    })
  })
}
// 新增设备
const refAddDeviceDialog = ref()
const addDevice = () => {
  refAddDeviceDialog.value.initDialog({ type: 'create' })
}

// 获取在用状态字典值
const getStatusDict = async () => {
  getDictByCode('onlineStatus').then((res: any) => {
    if (res.code === 200) {
      statusDict.value = res.data
      sessionStorage.setItem('onlineStatus', JSON.stringify(statusDict.value))
    }
  })
}
const getDeviceTypeDict = async () => {
  getDictByCode('deviceType').then((res: any) => {
    if (res.code === 200) {
      deviceTypeDict.value = res.data
      sessionStorage.setItem('deviceType', JSON.stringify(deviceTypeDict.value))
    }
  })
}
const getAllGroupList = async () => {
  await getGroupList({}).then((res: any) => {
    if (res.code === 200) {
      groupList.value = res.data.rows
    }
  })
}
const getDict = async () => {
  await getStatusDict()
  await getDeviceTypeDict()
  await getAllGroupList()
}

watch(() => cell.value, (val) => {
  switch (parseInt(val)) {
    case 1:
      searchQuery.value.beginCell = '0'
      searchQuery.value.endCell = '10'
      break

    case 2:
      searchQuery.value.beginCell = '0'
      searchQuery.value.endCell = '20'
      break

    case 3:
      searchQuery.value.beginCell = '0'
      searchQuery.value.endCell = '30'
      break

    case 4:
      searchQuery.value.beginCell = '0'
      searchQuery.value.endCell = '50'
      break

    default:
      delete searchQuery.value.beginCell
      delete searchQuery.value.endCell
      break
  }
})

onMounted(async () => {
  await getDict()
  searchList()
  window.addEventListener('resize', calcTableHeight)
})


const tableHeight = ref(400)
const calcTableHeight = () => {
  // 顶部高度
  const topHeight = 110
  // app-container的 padding距离
  const appPadding = 20
  // 查询组件的高度
  const searchDiv = document.getElementById('search-div-id')
  const searchHeight = searchDiv ? searchDiv.clientHeight : 0
  // 表格顶部的文字提示高度
  const tableTopHeight = 32 + 10
  // 表格表头
  const tableHeaderHeight = 40
  // 分页器的高度
  const tablePaginationHeight = 40
  // 判断数据长度
  const height = window.innerHeight - topHeight - appPadding - searchHeight - tableTopHeight - tableHeaderHeight - tablePaginationHeight
  if (dataList.value.length * 40 >= height) {
    // if (height < 200) {
    //   tableHeight.value = 200
    //   return
    // }
    tableHeight.value = height
  }
  else {
    tableHeight.value = dataList.value.length ? (dataList.value.length + 1) * 40 : 200
  }
}
onBeforeUnmount(() => {
  window.removeEventListener('resize', calcTableHeight)
})
</script>

<template>
  <app-container>
    <add-device-dialog ref="refAddDeviceDialog" :needGroup="true" @record-saved="searchList" />
    <!-- 批量下发配置弹窗 -->
    <batchconfig ref="batchConfigRef" />
    <!-- 筛选条件 -->
    <search-area :need-clear="true" @search="searchList" @clear="reset">
      <search-item>
        <el-select v-model="searchQuery.groupId" placeholder="请选择分组" clearable filterable style="width: 192px;">
          <el-option v-for="group in groupList" :key="group.id" :label="group.groupName" :value="group.id" />
        </el-select>
      </search-item>
      <search-item>
        <el-input v-model="searchQuery.devcode" placeholder="设备编号" clearable />
      </search-item>
      <search-item>
        <el-input v-model="searchQuery.imei" placeholder="设备IMEI号" clearable />
      </search-item>
      <search-item>
        <el-select v-model="searchQuery.deviceType" placeholder="设备类型" clearable style="width: 192px;">
          <el-option v-for="dict in deviceTypeDict" :key="dict.id" :label="dict.name" :value="dict.value" />
        </el-select>
      </search-item>
      <search-item>
        <el-select v-model="searchQuery.status" placeholder="设备状态" clearable style="width: 192px;">
          <!-- <el-option v-for="item in statusDict" :key="item.id" :value="item.value" :label="item.name" /> -->
          <el-option key="0" value="0" label="正常"></el-option>
          <el-option key="1" value="1" label="使用中"></el-option>
        </el-select>
      </search-item>

      <search-item>
        <el-select v-model="cell" placeholder="设备电量" clearable style="width: 192px;">
          <el-option v-for="item in cellLevelList" :key="item.value" :value="item.value" :label="item.name" />
        </el-select>
      </search-item>
    </search-area>

    <!-- 表格数据展示 -->
    <table-container title="设备列表">
      <!-- 表头区域 -->
      <template #btns-right>
        <el-button v-if="proxy.hasPerm(`/basic/device/add`)" type="primary" @click="addDevice">
          新增
        </el-button>
        <el-button type="primary" @click="batchAddDevice">
          导入
        </el-button>
        <el-button type="primary" @click="exportAllDevice">
          导出
        </el-button>
        <el-button type="primary" @click="downTemplate">
          模板下载
        </el-button>
        <el-button type="primary" @click="bacthConfig">
          批量下发配置
        </el-button>
        <!-- 导入上传组件 -->
        <input ref="fileRef" style="display: none;" type="file" accept=".xls,.xlsx" @change="onFileChange">

      </template>

      <!-- 表格区域 -->
      <normal-table :data="dataList" :columns="columns" :total="total" :query="searchQuery" :list-loading="loadingTable"
        @change="changePage" :height="tableHeight">
        <template #preColumns>
          <el-table-column label="序号" width="55" align="center">
            <template #default="scope">
              {{ (searchQuery.offset! - 1) * searchQuery.limit! + scope.$index + 1 }}
            </template>
          </el-table-column>
        </template>

        <template #columns>
          <el-table-column fixed="right" label="操作" align="center" width="130">
            <template #default="{ row }">
              <el-button size="small" type="primary" link @click="detail(row)">
                查看
              </el-button>
              <el-button v-if="proxy.hasPerm(`/basic/device/edit`)" size="small" type="primary" link
                @click="updateById(row)">
                编辑
              </el-button>
              <el-button v-if="proxy.hasPerm(`/basic/device/del`)" size="small" type="danger" link
                @click="deleteDeviceById(row)">
                删除
              </el-button>
            </template>
          </el-table-column>
        </template>
      </normal-table>
    </table-container>
  </app-container>
</template>