| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378 |
- <template>
- <div class="deviceList">
- <Search :onClickSearch="async () => { }" :onClickReset="async () => { }" />
- <div class="deviceList-table">
- <a-table :columns="columns" :data-source="data.device" :pagination="paginationProp" @change="refreshData"
- row-key="device_sn" :expandedRowKeys="expandRows" :row-selection="rowSelection" :rowClassName="rowClassName"
- :scroll="{ x: '100%', y: 500 }" :expandIcon="expandIcon" :loading="loading">
- <template v-for="col in ['nickname']" #[col]="{ text, record }" :key="col">
- <div>
- <a-input v-if="editableData[record.device_sn]" v-model:value="editableData[record.device_sn][col]" />
- <template v-else>
- <a-tooltip :title="text">
- {{ text }}
- </a-tooltip>
- </template>
- </div>
- </template>
- <template v-for="col in ['sn', 'workspace']" #[col]="{ text }" :key="col">
- <a-tooltip :title="text">
- <span>{{ text }}</span>
- </a-tooltip>
- </template>
- <!-- 固件版本 -->
- <template #firmware_version="{ record }">
- <span v-if="record.domin === 3">
- <DeviceFirmwareUpgrade :device="record" class="table-flex-col" @device-upgrade="onDeviceUpgrade" />
- </span>
- <span v-else>
- {{ record.firmware_version }}
- </span>
- </template>
- <!-- 固件升级 -->
- <template #firmware_status="{ text }">
- <div v-if="text === -1">
- 不支持
- </div>
- <div v-else>
- {{ DeviceFirmwareStatus[text] }}
- </div>
- </template>
- <!-- 状态 -->
- <template #status="{ text }">
- <span v-if="text" class="flex-row flex-align-center">
- <span class="mr5" style="width: 12px; height: 12px; border-radius: 50%; background-color: green;" />
- <span>在线</span>
- </span>
- <span class="flex-row flex-align-center" v-else>
- <span class="mr5" style="width: 12px; height: 12px; border-radius: 50%; background-color: red;" />
- <span>离线</span>
- </span>
- </template>
- <!-- 操作 -->
- <template #action="{ record }">
- <!-- 编辑态操作 -->
- <div v-if="editableData[record.device_sn]">
- <a-tooltip title="确定">
- <CheckOutlined style="color: #28d445;margin-right: 10px;" @click="save(record)" />
- </a-tooltip>
- <a-tooltip title="取消">
- <CloseOutlined style="color: #e70102;" @click="() => delete editableData[record.device_sn]" />
- </a-tooltip>
- </div>
- <!-- 非编辑态操作 -->
- <div v-else class="flex-align-center flex-row" style="color: #2d8cf0">
- <a-tooltip title="设备日志">
- <CloudServerOutlined style="margin-right: 10px;" @click="showDeviceLogUploadRecord(record)" />
- </a-tooltip>
- <a-tooltip title="告警信息">
- <FileSearchOutlined style="margin-right: 10px;" @click="showHms(record)" />
- </a-tooltip>
- <a-tooltip title="编辑">
- <EditOutlined style="margin-right: 10px;" @click="edit(record)" />
- </a-tooltip>
- <a-tooltip title="删除">
- <DeleteOutlined @click="onClickDelete(record)" />
- </a-tooltip>
- </div>
- </template>
- </a-table>
- <!-- 设备升级 -->
- <DeviceFirmwareUpgradeModal title="设备升级" v-model:visible="deviceFirmwareUpgradeModalVisible"
- :device="selectedDevice" @ok="onUpgradeDeviceOk" />
- <!-- 设备日志上传记录 -->
- <DeviceLogUploadRecordDrawer v-model:visible="deviceLogUploadRecordVisible" :device="currentDevice" />
- <!-- hms 信息 -->
- <DeviceHmsDrawer v-model:visible="hmsVisible" :device="currentDevice" />
- </div>
- </div>
- </template>
- <script lang="ts" setup>
- import { h, onMounted, reactive, ref, UnwrapRef } from 'vue'
- import { Modal, notification } from 'ant-design-vue'
- import { EditOutlined, CheckOutlined, CloseOutlined, DeleteOutlined, FileSearchOutlined, CloudServerOutlined } from '@ant-design/icons-vue'
- import Search from './components/Search.vue'
- import { getBindingDevices, unbindDevice, updateDevice } from '/@/api/manage'
- import { Device, DeviceFirmwareStatus, DeviceFirmwareStatusEnum } from '/@/types/device'
- import DeviceFirmwareUpgrade from '/@/components/devices/device-upgrade/DeviceFirmwareUpgrade.vue'
- import DeviceFirmwareUpgradeModal from '/@/components/devices/device-upgrade/DeviceFirmwareUpgradeModal.vue'
- import { useDeviceFirmwareUpgrade } from '/@/components/devices/device-upgrade/use-device-upgrade'
- import { useDeviceUpgradeEvent } from '/@/components/devices/device-upgrade/use-device-upgrade-event'
- import { DeviceCmdExecuteInfo, DeviceCmdExecuteStatus } from '/@/types/device-cmd'
- import DeviceLogUploadRecordDrawer from '/@/components/devices/device-log/DeviceLogUploadRecordDrawer.vue'
- import DeviceHmsDrawer from '/@/components/devices/device-hms/DeviceHmsDrawer.vue'
- import { IPage } from '/@/api/http/type'
- import { EDeviceTypeName, ELocalStorageKey } from '/@/types'
- const loading = ref(true)
- const columns = [
- {
- title: '设备型号',
- dataIndex: 'device_name',
- width: 150,
- ellipsis: true,
- sorter: (a: any, b: any) => a.device_name.localeCompare(b.device_name),
- },
- {
- title: '设备SN',
- dataIndex: 'device_sn',
- width: 200,
- ellipsis: true,
- slots: { customRender: 'sn' }
- },
- {
- title: '设备名称',
- dataIndex: 'nickname',
- width: 150,
- ellipsis: true,
- sorter: (a: any, b: any) => a.nickname.localeCompare(b.nickname),
- slots: { customRender: 'nickname' }
- },
- {
- title: '固件版本',
- dataIndex: 'firmware_version',
- width: 150,
- ellipsis: true,
- slots: { customRender: 'firmware_version' },
- },
- {
- title: '固件升级',
- dataIndex: 'firmware_status',
- width: 150,
- ellipsis: true,
- slots: { customRender: 'firmware_status' },
- },
- {
- title: '当前状态',
- dataIndex: 'status',
- width: 100,
- ellipsis: true,
- slots: { customRender: 'status' }
- },
- {
- title: '加入项目时间',
- dataIndex: 'bound_time',
- width: 200,
- sorter: (a: any, b: any) => a.bound_time.localeCompare(b.bound_time),
- },
- {
- title: '最后在线时间',
- dataIndex: 'login_time',
- width: 200,
- sorter: (a: any, b: any) => a.login_time.localeCompare(b.login_time),
- },
- {
- title: '操作',
- dataIndex: 'actions',
- fixed: 'right',
- width: 150,
- slots: { customRender: 'action' },
- },
- ]
- const expandIcon = (props: any) => {
- if (!props.expanded) {
- return h('div',
- {
- style: 'border-left: 2px solid rgb(200,200,200); border-bottom: 2px solid rgb(200,200,200); height: 16px; width: 16px; float: left;',
- class: 'mt-5 ml0',
- })
- }
- }
- const rowClassName = (record: any, index: number) => {
- const className = []
- if ((index & 1) === 0) {
- className.push('table-striped')
- }
- return className.toString().replaceAll(',', ' ')
- }
- const expandRows = ref<string[]>([])
- const data: {
- device: Device[]
- } = reactive({
- device: []
- })
- const paginationProp = reactive({
- pageSizeOptions: ['20', '50', '100'],
- showQuickJumper: true,
- showSizeChanger: true,
- pageSize: 20,
- current: 1,
- total: 0
- })
- // 获取分页信息
- function getPaginationBody() {
- return {
- page: paginationProp.current,
- page_size: paginationProp.pageSize
- } as IPage
- }
- const rowSelection = {
- onChange: (selectedRowKeys: (string | number)[], selectedRows: []) => {
- console.log(`selectedRowKeys: ${selectedRowKeys}`, 'selectedRows: ', selectedRows)
- },
- onSelect: (record: any, selected: boolean, selectedRows: []) => {
- console.log(record, selected, selectedRows)
- },
- onSelectAll: (selected: boolean, selectedRows: [], changeRows: []) => {
- console.log(selected, selectedRows, changeRows)
- },
- getCheckboxProps: (record: any) => ({
- disabled: record.domain !== EDeviceTypeName.Dock,
- }),
- }
- const workspaceId: string = localStorage.getItem(ELocalStorageKey.WorkspaceId) || ''
- const editableData: UnwrapRef<Record<string, Device>> = reactive({})
- // 设备升级
- const {
- deviceFirmwareUpgradeModalVisible,
- selectedDevice,
- onDeviceUpgrade,
- onUpgradeDeviceOk
- } = useDeviceFirmwareUpgrade(workspaceId)
- function onDeviceUpgradeWs(payload: DeviceCmdExecuteInfo) {
- updateDevicesByWs(data.device, payload)
- }
- function updateDevicesByWs(devices: Device[], payload: DeviceCmdExecuteInfo) {
- if (!devices || devices.length <= 0) {
- return
- }
- for (let i = 0; i < devices.length; i++) {
- if (devices[i].device_sn === payload.sn) {
- if (!payload.output) return
- const { status, progress, ext } = payload.output
- if (status === DeviceCmdExecuteStatus.Sent || status === DeviceCmdExecuteStatus.InProgress) { // 升级中
- const rate = ext?.rate ? (ext.rate / 1024).toFixed(2) + 'kb/s' : ''
- devices[i].firmware_status = DeviceFirmwareStatusEnum.DuringUpgrade
- devices[i].firmware_progress = (progress?.percent || 0) + '% ' + rate
- } else { // 终态:成功,失败,超时
- if (status === DeviceCmdExecuteStatus.Failed || status === DeviceCmdExecuteStatus.Timeout) {
- notification.error({
- message: `(${payload.sn}) Upgrade failed`,
- description: `Error Code: ${payload.result}`,
- duration: null
- })
- }
- // 拉取列表
- getDevices(true)
- }
- return
- }
- if (devices[i].children) {
- updateDevicesByWs(devices[i].children || [], payload)
- }
- }
- }
- useDeviceUpgradeEvent(onDeviceUpgradeWs)
- // 获取设备列表信息
- function getDevices(closeLoading?: boolean) {
- if (!closeLoading) {
- loading.value = true
- }
- getBindingDevices(workspaceId, getPaginationBody()).then(res => {
- if (res.code !== 0) {
- return
- }
- const resData: Device[] = res.data.list
- expandRows.value = []
- resData.forEach((val: any) => {
- if (val.children) {
- val.children = [val.children]
- expandRows.value.push(val.device_sn);
- }
- })
- data.device = resData;
- paginationProp.total = res.data.pagination.total
- paginationProp.current = res.data.pagination.page
- paginationProp.pageSize = res.data.pagination.page_size
- loading.value = false
- })
- }
- function refreshData(page: any) {
- paginationProp.current = page?.current!
- paginationProp.pageSize = page?.pageSize!
- getDevices()
- }
- // 编辑
- function edit(record: Device) {
- editableData[record.device_sn] = record
- }
- // 保存
- function save(record: Device) {
- delete editableData[record.device_sn]
- updateDevice({ nickname: record.nickname }, workspaceId, record.device_sn)
- }
- // 点击删除
- const onClickDelete = (record: Device) => {
- Modal.confirm({
- title: '提示',
- content: `确定删除${record.device_name}吗?`,
- onOk: async () => {
- unbindDevice(record.device_sn).then(res => {
- if (res.code !== 0) {
- return
- }
- getDevices()
- })
- },
- });
- }
- const currentDevice = ref({} as Device)
- // 设备日志
- const deviceLogUploadRecordVisible = ref(false)
- function showDeviceLogUploadRecord(dock: Device) {
- deviceLogUploadRecordVisible.value = true
- currentDevice.value = dock
- }
- // 健康状态
- const hmsVisible = ref<boolean>(false)
- function showHms(dock: Device) {
- hmsVisible.value = true
- currentDevice.value = dock
- }
- onMounted(() => {
- getDevices()
- })
- </script>
- <style lang="scss">
- .deviceList {
- padding: 20px;
- }
- .ant-table {
- border-top: 1px solid rgb(0, 0, 0, 0.06);
- border-bottom: 1px solid rgb(0, 0, 0, 0.06);
- }
- .ant-table-tbody tr td {
- border: 0;
- }
- .table-striped {
- background-color: #f7f9fa;
- }
- </style>
|