<template>
  <div class="flex-col gap-16 wh-full">
    <el-button type="primary" @click="onBack" class="w-150px">
      <i class="i-line-md:arrow-left"></i>返回站点数据
    </el-button>
    <EdfsWrap title="设备列表" class="flex-1" useScrollBar>
      <template #title-right>
        <template v-if="isBatchTransfer || isBatchUpgrade">
          <el-button type="primary" @click="onBatchSave"> 确定{{ batchText }} </el-button>
          <el-button type="info" @click="onBatchCancel"> 取消 </el-button>
        </template>
        <template v-else>
          <el-button type="primary" @click="onBatchTransfer"> <i class="i-mdi:database-arrow-right-outline mr-1" />
            批量迁移 </el-button>
          <el-button v-if="isonLineTransfer" type="primary" @click="onBatchUpgrade"> <i
              class="i-codicon:chip mr-1" />批量升级
          </el-button>
        </template>
      </template>
      <div class="device-list-wrap">
        <el-checkbox-group v-model="checkDeviceList">
          <div class="device-item" v-for="item in devices">
            <div class="device-item-header">
              <div class="flex items-center">
                <el-checkbox :value="item.sn" v-if="(isBatchTransfer || isBatchUpgrade) && item.status !== '离线'">
                  <div>设备ID: {{ item.sn }}</div>
                </el-checkbox>
                <div v-else class="h-32 leading-32px">
                  <div>设备ID: {{ item.sn }}</div>
                </div>
              </div>
              <div class="flex items-center gap-col-2" v-if="!(isBatchTransfer || isBatchUpgrade)">
                <el-tooltip content="数据迁移" v-if="isonLineTransfer ? item.status === '在线' : true">
                  <i class="i-mdi:database-arrow-right-outline :hover:color-[#8ACE6A] color-[#4B9E5F] cursor-pointer text-20px"
                    @click="onTransfer(item)"></i>
                </el-tooltip>
                <el-tooltip content="固件升级" v-if="isonLineTransfer && item.status === '在线'">
                  <i class="i-codicon:chip :hover:color-[#8ACE6A] color-[#4B9E5F] cursor-pointer text-20px"
                    @click="onFirmwareUpload([item])"></i>
                </el-tooltip>
                <el-tooltip content="详情">
                  <div
                    class="i-material-symbols:info-outline :hover:color-[#8ACE6A] color-[#4B9E5F] cursor-pointer text-20px"
                    @click="onDeviceDetails(item)"></div>
                </el-tooltip>
              </div>
            </div>

            <div class="device-item-body relative">
              <template v-if="isonLineTransfer">
                <template v-for="key in Object.keys(onlineDeviceMap)">
                  <div class="info-item" v-if="isonLineTransfer && key === 'status'">
                    <div>{{ onlineDeviceMap.status }}:</div>
                    <el-tag :type="item.status === '在线' ? 'success' : 'danger'">
                      {{ item.status }}
                    </el-tag>
                  </div>
                  <div class="info-item" v-else>
                    <div>{{ onlineDeviceMap[key as keyof typeof onlineDeviceMap] }}:</div>
                    <div>{{ item[key] }}</div>
                  </div>
                </template>
              </template>
              <template v-else>
                <template v-for="key in Object.keys(offlineDeviceMap)">
                  <div class="info-item" v-if="key === 'create_time'">
                    <div>
                      {{ offlineDeviceMap[key as keyof typeof offlineDeviceMap] }}:
                    </div>
                    <div>{{ dayjs(item[key]).format('YYYY-MM-DD HH:mm:ss') }}</div>
                  </div>
                  <div class="info-item" v-else>
                    <div>
                      {{ offlineDeviceMap[key as keyof typeof offlineDeviceMap] }}:
                    </div>
                    <div>{{ item[key] }}</div>
                  </div>
                </template>
              </template>
              <div class="absolute l-0 t-0 w-full h-full z-10 bg-#FFF-90"
                v-if="['updating', 'pending', 'rejected', 'timeout'].includes(item.upFirmware)">
                <div class="i-material-symbols-light:close absolute-rt text-base text-gray-950 cursor-pointer"
                  v-if="['timeout', 'rejected'].includes(item.upFirmware)" @click="upFirmwareSucceed(item.sn)"></div>
                <template v-if="item.upFirmware === 'updating'">
                  <div class="device-item-body">
                    <div class="info-item">
                      <div>当前步骤:</div>
                      <div>{{ item.upFirmwareStatus?.step ?? '--' }}</div>
                    </div>
                    <div class="info-item">
                      <div>当前进度:</div>
                      <el-progress class="flex-1" :stroke-width="12" :show-text="true"
                        :percentage="item.upFirmwareStatus?.progress || 0" />
                    </div>
                  </div>
                </template>
                <template v-else-if="item.upFirmware === 'pending'">
                  <div class="w-full h-full flex items-center justify-center">
                    <div class="font-400 text-base text-[#4B9E5F]">等待升级中...</div>
                  </div>
                </template>
                <template v-if="item.upFirmware === 'rejected'">
                  <div class="device-item-body">

                    <div class="info-item">
                      <div>错误发生步骤:</div>
                      <div class="text-red">
                        {{
                          upgradeProgressStatusMap.find(
                            r => r.status == item.upFirmwareStatus?.step
                          )?.text ?? '--'
                        }}失败
                      </div>
                    </div>
                    <div class="info-item">
                      <div>错误信息:</div>
                      <div>{{ item.upFirmwareStatus?.errMsg ?? '--' }}</div>
                    </div>
                  </div>
                </template>
                <template v-if="item.upFirmware === 'timeout'">
                  <div class="w-full h-full flex items-center justify-center">
                    <div class="font-400 text-base text-[#E6A23C]">升级超时</div>
                  </div>
                </template>
              </div>
            </div>
          </div>
        </el-checkbox-group>
      </div>
    </EdfsWrap>
    <TransferMask v-model="isShowTransferMask" :transferLoading="transferLoading" @close="closeTransferMask">
      <template v-if="curTransfer === 'export'">
        <div class="flex-col gap-col-10 h-full w-56% justify-center">
          <div class="flex items-center gap-col-1">
            <div class="flex-1 flex items-center">
              <el-progress :percentage="100" class="flex-1" :stroke-width="18" :text-inside="true"
                :striped="transferStatus === 'progress'" :striped-flow="transferStatus === 'progress'" :duration="20"
                :status="['progress', 'success', undefined].includes(transferStatus)
                  ? 'success'
                  : 'exception'
                  ">
                {{
                  transferStatusMap[transferStatus as keyof typeof transferStatusMap] ?? ''
                }}

              </el-progress>
            </div>
            <el-button v-if="transferStatus === 'progress'" type="primary" @click="onStopTransfer">停止迁移</el-button>
          </div>
          <div class="transfer-log-wrap h-490 flex-col">
            <div class="text-16px font-500">迁移日志</div>
            <el-scrollbar class="flex-1">
              <div v-for="i in curTransferLog" :class="i.status === 'failed' ? 'text-red-500' : ''"
                class="text-gray-600">
                {{ i.msg }}
              </div>
            </el-scrollbar>
          </div>
        </div>
      </template>
      <template v-else-if="curTransfer === 'import'">
        <div class="flex-col gap-col-10 h-full w-56% justify-center">
          <div class="flex items-center gap-col-1">
            <div class="flex-1  items-center">
              <el-progress :percentage="100" :status="['progress', 'success', undefined].includes(onOffDeviceTransferStatus)
                ? 'success'
                : 'exception'
                " class="flex-1" :stroke-width="18" :text-inside="true"
                :striped="onOffDeviceTransferStatus === 'progress'"
                :striped-flow="onOffDeviceTransferStatus === 'progress'" :duration="20">

                <div class="text-16px font-500"> {{ !!onOffDeviceTransferStatus ? onOffDeviceTransferStatus ===
                  'progress'
                  ? '数据导入中' : '数据导入完成' : '数据导入中' }}</div>

              </el-progress>
            </div>
          </div>
          <div class="h-490 border-radius-8px bg-[#F9FAFB] p-10 flex-col">
            <div class="text-16px font-500">迁移日志</div>
            <el-scrollbar class="flex-1">
              <div v-for="i in siteTransferLogList" :class="i.status === 'error' ? 'text-red-500' : ''"
                class="text-gray-600">
                【{{ i.device.sn }}】：{{ i.msg }}
              </div>
            </el-scrollbar>
          </div>
        </div>
      </template>

    </TransferMask>

  </div>

  <OnLineTransferDlg ref="onLineTransferDlgRef" @on-save="onLineDeviceTransfer" :is-batch-transfer="isBatchTransfer" />
  <OffTransferDlg ref="offTransferDlg" :isBatchTransfer="false" :siteInfo="siteInfo" @on-save="onOffDeviceTransfer" />
  <DeviceDrawer v-model="isShowDetails" ref="deviceDrawerRef" :siteInfo="siteInfo" :is-transfer="isonLineTransfer" />
</template>

<script setup lang="ts">
import dayjs from 'dayjs'
import TransferMask from './components/transferMask.vue'
import OnLineTransferDlg from './components/onLineTransferDlg.vue'
import ZMQWorker from '@/composables/useZMQJsonWorker'
import OffTransferDlg from './components/offTransferDlg.vue'

import {
  getPubInitData,
  ZmqMsgResultType,
  type PublishMsg,
  type PubMsgData,
  type TimeoutMsg,
} from '@/utils/zmq'
import { useTransferDataStore } from '@/stores/transferData'
import { storeToRefs } from 'pinia'
import type {
  IOfflineDevice,
  IOnlineDevice,
  IUpFirmwareStatus,
  UpFirmwarsDevice,
} from './type'
import { useMessage } from '@/composables/useMessage'
import { getDeviceList, type ISite } from '@/api/module/transfer'
import DeviceDrawer from './components/deviceDrawer.vue'

import {
  getFirmwareUpTopic,
  getTransferTopic,
  postFirmwareUpTopic,
  postTransferTopic,
  upgradeProgressStatusMap,
} from './utils'
import { getFirmwarePath } from '@/api/module/firmware'
const onLineTransferDlgRef = ref<typeof OnLineTransferDlg>()
const router = useRouter()
const route = useRoute()
const siteInfo = ref<ISite>(
  route.query.site ? JSON.parse(route.query.site as string) : null
)
const type = ref<'export' | 'details'>(route.query.type as 'export' | 'details')

const isonLineTransfer = computed(() => type.value === 'export')

const isShowTransferMask = ref(false)

const message = useMessage()

const worker = ZMQWorker.getInstance()

const transferDataStore = useTransferDataStore()
const { upFirmwarePending, upFirmwareReset, upFirmwareStatus, upFirmwareSucceed, upFirmwareStatusReject, upFirmwareTimeout } =
  transferDataStore
const { devicesMap } = storeToRefs(transferDataStore)

const transferStatusMap = {
  progress: '迁移中',
  success: '迁移成功',
  failed: '迁移失败',
  timeout: '迁移超时',
}

const exportPubDeviceMap = new Map<string, { device: IOnlineDevice; action: 'export' }>()

const curTransferLog = ref<
  { msg: string; host: string; status: 'success' | 'padding' | 'failed' }[]
>([])

const transferStatus = ref<'progress' | 'success' | 'failed' | 'timeout' | undefined>()

const devices = computed(() => {
  return isonLineTransfer.value ? Array.from(devicesMap.value.values()) : offLineDeviceList.value
}) as Ref<any[]>

const transferLoading = ref(false)

const curTransfer = ref<'import' | 'export'>()
function openTransferMask(status: 'import' | 'export') {
  isShowTransferMask.value = true
  curTransfer.value = status
  transferLoading.value = true
}

function closeTransferMask() {
  curTransfer.value = undefined
  isShowTransferMask.value = false
  transferLoading.value = false
  curTransferLog.value = []
  transferStatus.value = undefined
  siteTransferLogList.value = []
  pubIdWithOffDevice.clear()
  exportPubDeviceMap.clear()
}

function onLineDeviceTransfer(msg: PublishMsg<'export'>, device: IOnlineDevice) {
  curTransferLog.value = []
  openTransferMask('export')
  worker.publish(postTransferTopic, msg, true, zmqTimeoutCb)
  exportPubDeviceMap.set(msg.id, { device, action: 'export' })
  worker.subscribe(getTransferTopic, zmqExportCb, msg.id)

  if (isBatchTransfer.value) {
    onBatchCancel()
  }
}

const statusMap = {
  200: 'success',
  1002: 'padding',
  1003: 'failed',
}


function zmqExportCb(msg: PubMsgData) {
  if (!isonLineTransfer.value) return
  const { feedback, result, id } = msg
  transferLoading.value = false
  if (feedback && feedback[0]) {
    const status = feedback[1]
      ? (statusMap[feedback[1] as keyof typeof statusMap] as
        | 'success'
        | 'padding'
        | 'failed')
      : 'failed'
    curTransferLog.value.push({
      msg: `主机【${feedback[0]}】: ${feedback[2]}`,
      host: feedback[0],
      status,
    })
  }
  transferStatus.value = 'progress'
  if (result !== 'progress') {

    const curMsgInfo = exportPubDeviceMap.get(id)!
    if (!curMsgInfo) return
    const { device, action } = curMsgInfo
    if (device && action === 'export') {
      if (result === 'success') {
        const res = setTransferStatus()
        if (res === 0) {
          message.success(`迁移成功`)
          transferStatus.value = 'success'
        } else {
          message.error(`迁移失败,请检查迁移日志`)
          transferStatus.value = 'failed'
        }
      } else if (['failed', 'failure'].includes(result)) {

        message.error(`迁移失败`)
        transferStatus.value = 'failed'
      }
      exportPubDeviceMap.delete(msg.id)
    }
  }
}

function setTransferStatus() {
  const failed = curTransferLog.value.filter(i => i.status === 'failed')
  for (const f of failed) {
    curTransferLog.value.forEach(j => {
      if (f.host === j.host) {
        j.status = 'failed'
      }
    })
  }
  return failed.length
}

function onStopTransfer() {
  message.confirm('是否确认停止迁移?').then(() => {
    const msg = getPubInitData<'cancel'>('cancel', [], 'no')
    worker.publish(postTransferTopic, msg)
    message.success('迁移已取消')
    exportPubDeviceMap.clear()
  })
}


function zmqTimeoutCb(msg: TimeoutMsg) {
  const { device, action } = exportPubDeviceMap.get(msg.timeoutId)!
  if (device && action === 'export') {
    message.error(`迁移超时,请重新稍后尝试`)
    exportPubDeviceMap.delete(msg.timeoutId)
    closeTransferMask()
  }
}

const onlineDeviceMap: Record<
  keyof Omit<
    IOnlineDevice,
    'lastUpdated' | 'sn' | 'isChecked' | 'upFirmware' | 'upFirmwareStatus'
  >,
  string
> = {
  status: '状态',
  stationName: '站点名称',
  clientIp: '客户端IP',
  footprint: '数据占用空间',
}
const offlineDeviceMap: Record<
  keyof Pick<IOfflineDevice, 'stationName' | 'db' | 'create_time'>,
  string
> = {
  stationName: '站点名称',
  db: '数据库',
  create_time: '创建时间',
}

const checkDeviceList = ref<string[]>([])

const isBatchTransfer = ref(false)
function onBatchTransfer() {
  checkDeviceList.value = []
  isBatchTransfer.value = true
}

function onBatchTransferSave(checkDeviceList: IOnlineDevice[] | IOfflineDevice[]) {
  if (isonLineTransfer.value) {
    const checkList = checkDeviceList as IOnlineDevice[]
    const clientIpList = checkList.map(item => item?.clientIp).join(',')
    const pathList = checkList
      .map(item => `${item?.stationName}/${item?.sn}`)
      .filter(Boolean)
      .join(',')

    onLineTransferDlgRef.value?.open(checkList[0], clientIpList, pathList)
  } else {
    offTransferDlg.value?.open(checkDeviceList, true)
  }
}

const isBatchUpgrade = ref(false)
function onBatchUpgrade() {
  checkDeviceList.value = []
  isBatchUpgrade.value = true
}

const batchText = computed(() => {
  return isBatchTransfer.value ? '迁移' : '升级'
})

function onBatchSave() {
  if (!checkDeviceList.value.length) {
    message.error(`请选择要${batchText.value}的设备`)
    return
  }

  const checkList = isonLineTransfer.value
    ? getOnlineDeviceList()
    : getOfflineDeviceList()

  if (isBatchTransfer.value) {
    onBatchTransferSave(checkList)
  }

  if (isBatchUpgrade.value && isonLineTransfer.value) {
    onFirmwareUpload(checkList as IOnlineDevice[])
  }
}

function getOnlineDeviceList(): IOnlineDevice[] {
  return checkDeviceList.value
    .map(sn => {
      return devicesMap.value.get(sn) ?? undefined
    })
    .filter(Boolean) as IOnlineDevice[]
}

function getOfflineDeviceList(): IOfflineDevice[] {
  return offLineDeviceList.value.filter(item =>
    checkDeviceList.value.includes(item.sn)
  )
}

function onBatchCancel() {
  isBatchTransfer.value = false
  isBatchUpgrade.value = false
  checkDeviceList.value = []
}
function onTransfer(item: IOnlineDevice) {
  if (isonLineTransfer.value) {
    onLineTransferDlgRef.value?.open(item)
  } else {
    offTransferDlg.value?.open([item])
  }
}

function onBack() {
  router.push('/station')
}

// 监听页面刷新
window.onbeforeunload = function () {
  stop()
}

onBeforeRouteLeave(async (to, from, next) => {
  if (transferStatus.value === 'progress') {
    try {
      await message.confirm('当前迁移尚未完成，是否确认离开？')
      window.location.href = to.fullPath
    } catch (error) {
      next(false)
    }
  } else {
    next()
  }
})

const offLineDeviceList = ref<IOfflineDevice[]>([])

async function loadDeviceList() {
  const res = await getDeviceList(siteInfo.value.name)
  if (res.code === 200 || res.code === 0) {
    offLineDeviceList.value = res.data
  }
}

const firmwarePath = ref('')

onMounted(async () => {
  if (!isonLineTransfer.value) {
    loadDeviceList()
  } else {
    const res = await getFirmwarePath()
    if (res.code === 200 || res.code === 0) {
      firmwarePath.value = res.data.path
    }
  }
})

const isShowDetails = ref(false)
const deviceDrawerRef = ref<typeof DeviceDrawer>()
function onDeviceDetails(item: IOfflineDevice) {
  deviceDrawerRef.value?.openFullScreen()
  deviceDrawerRef.value?.open(item)
}

const isCanFirmwareUpload = computed(() => !!firmwarePath.value && isonLineTransfer.value)

const upgradeSnList = ref<string[]>([])
const upgradePubDeviceMap = new Map<string, UpFirmwarsDevice>()
function onFirmwareUpload(devices: IOnlineDevice[]) {
  upgradeSnList.value = []
  if (!isCanFirmwareUpload.value) {
    message.error('升级失败,请检查固件路径')
    onBatchCancel()
    return
  }
  let deviceSn = devices[0].sn

  if (isBatchUpgrade.value) {
    deviceSn = devices.map(item => item.sn).join(',')
  }
  const msg = getPubInitData<'upgrade'>('upgrade', [deviceSn, firmwarePath.value])
  for (const device of devices) {
    upgradePubDeviceMap.set(msg.id, {
      device: device,
      action: 'upgrade',
    })
  }
  worker.publish(postFirmwareUpTopic, msg, true, firmwareUpTimeoutCb, true)
  worker.subscribe(getFirmwareUpTopic, zmqUpgradeCb, msg.id)
  upgradeSnList.value = deviceSn.split(',')

  upFirmwarePending(upgradeSnList.value)
  onBatchCancel()
}
function firmwareUpTimeoutCb(msg: TimeoutMsg) {
  const { device, action } = upgradePubDeviceMap.get(msg.timeoutId)!
  if (device && action === 'upgrade') {
    const timeoutUpgradeSnList = upgradeSnList.value
    if (timeoutUpgradeSnList.length === 0) {
      upFirmwareReset(upgradeSnList.value)
      upgradePubDeviceMap.delete(msg.timeoutId)
      return
    }

    for (const deviec of timeoutUpgradeSnList) {
      upFirmwareTimeout(deviec)
    }
    upgradePubDeviceMap.delete(msg.timeoutId)
    message.warning(`固件升级超时,请稍后重试`)
  }
}

function zmqUpgradeCb(msg: PubMsgData) {
  if (!isonLineTransfer.value) return
  const status = msg.result
  const deviceSn = msg.feedback[0]
  const progressStatus = msg.feedback[1] as number
  const progress = msg.feedback[2] || undefined
  const curentDevice = upgradePubDeviceMap.get(msg.id)
  if (curentDevice && curentDevice.action === 'upgrade') {
    const { device } = curentDevice
    if (device) {
      if (status === 'progress') {
        upFirmwareStatus(deviceSn, msg.feedback)
        if (progressStatus === 4 && progress === 100) {
          upFirmwareSucceed(deviceSn)
        }
      }
    }
    if (status === 'success' || status === 'error') {
      upFirmwareStatus(deviceSn, msg.feedback)
      if (status === 'error') {
        upFirmwareStatusReject(deviceSn, msg.feedback)
      }
      upgradeSnList.value = upgradeSnList.value.filter(item => item !== deviceSn)
    }
  }
}

//  ================离线数据导入=========

const offTransferDlg = ref<typeof OffTransferDlg>()

const pubIdWithOffDevice = new Map<string, { offDevice: IOfflineDevice; action: 'import' }>()
const importQueue = ref<{ msg: PublishMsg<'import'>; offDevice: IOfflineDevice }[]>([]) // 队列
const isImporting = ref(false)

async function processNextImport() {
  if (importQueue.value.length === 0 || isImporting.value) {
    onOffDeviceTransferStatus.value = 'success'
    return
  }

  isImporting.value = true
  const { msg, offDevice } = importQueue.value[0]

  pubIdWithOffDevice.set(msg.id, { offDevice, action: 'import' })
  worker.publish(postTransferTopic, msg, true, zmqImportTimeoutCb)
  worker.subscribe(getTransferTopic, zmqImportCb, msg.id)

}

function onOffDeviceTransfer(msg: PublishMsg<'import'>[], offDevice: IOfflineDevice[]) {
  // 将设备和消息添加到队列中
  msg.forEach((m, index) => {
    importQueue.value.push({ msg: m, offDevice: offDevice[index] })
  })

  // 开始处理队列
  processNextImport()
  onBatchCancel()
  openTransferMask('import')
}

const siteTransferLogList = ref<Array<{
  msg: string
  device: IOfflineDevice
  status: 'success' | 'timeout' | 'error'
}>>([])

const onOffDeviceTransferStatus = ref<'progress' | 'success' | undefined>()
function zmqImportCb(msg: PubMsgData) {
  const { id, feedback, result, code } = msg
  transferLoading.value = false
  const { offDevice, action } = pubIdWithOffDevice.get(id)!
  if (action !== 'import' || !offDevice) return
  if (code === ZmqMsgResultType.PROGRESS) {
    onOffDeviceTransferStatus.value = 'progress'
    const log: string = Array.isArray(feedback) ? feedback[0] || '' : ''
    siteTransferLogList.value.push({
      msg: log,
      device: offDevice,
      status: 'success'
    })
  }

  if (code !== ZmqMsgResultType.PROGRESS) {
    // 从队列中移除已处理的消息
    importQueue.value.shift()
    isImporting.value = false
    if (code === ZmqMsgResultType.ERROR) {
      siteTransferLogList.value.push({
        msg: `数据导入失败,请稍后重试消息结果:${result}`,
        device: offDevice,
        status: 'error'
      })
    }
    // 处理队列中的下一个消息
    processNextImport()
  }
}

function zmqImportTimeoutCb(msg: TimeoutMsg) {
  const { offDevice, action } = pubIdWithOffDevice.get(msg.timeoutId)!
  if (offDevice && action === 'import') {
    message.error(`站点:${offDevice.sn}数据导出超时,请稍后重试`)
    transferLoading.value = false

    pubIdWithOffDevice.delete(msg.timeoutId)
    siteTransferLogList.value.push({
      msg: `数据导入超时,请稍后重试`,
      device: offDevice,
      status: 'error'
    })
    // 从队列中移除超时的项目
    importQueue.value.shift()
    isImporting.value = false

    // 处理队列中的下一个项目
    processNextImport()
  }
}

//  ================ 离线数据导入 end =========
</script>

<style scoped lang="scss">
.transfer-log-wrap {
  margin-top: 10px;
  @apply border-radius-8px bg-[#F9FAFB] p-10;

  :deep(.el-scrollbar) {
    height: calc(100% - 20px);
  }
}

.device-list-wrap {
  @apply wh-full;

  :deep(.el-checkbox-group) {
    @apply wh-full flex flex-wrap gap-col-6 gap-row-4;
  }

  :deep(.el-checkbox__inner) {
    width: 18px;
    height: 18px;

    &::after {
      left: 6px;
      top: 3px;
    }
  }

  :deep(.el-checkbox__label) {
    @apply text-14px font-500 text-[#313131];
  }

  :deep(.el-checkbox__input.is-checked + .el-checkbox__label) {
    color: var(--el-color-primary);
  }

  .device-item {
    @apply w-289 h-160 border border-solid border-[#E0E0E0] rounded-8px p-x-14 p-y-10 flex-col;

    .device-item-header {
      @apply w-full text-black text-18px font-500 flex items-center justify-between;

      .info {
        font-size: 14px;
        color: #f1bf63;
        cursor: pointer;
        text-decoration: underline;

        &:hover {
          color: #8ace6a;
        }
      }
    }

    .device-item-body {
      @apply flex-col m-t-10 text-sm gap-6;

      .info-item {
        @apply flex items-center gap-col-2;
      }
    }
  }
}
</style>
