|
|
|
@ -3,18 +3,27 @@
@@ -3,18 +3,27 @@
|
|
|
|
|
<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> |
|
|
|
|
<EdfsWrap |
|
|
|
|
:title="isonLineTransfer ? `在线设备列表` : `历史设备列表`" |
|
|
|
|
class="flex-1" |
|
|
|
|
useScrollBar |
|
|
|
|
:shapeColor="isonLineTransfer ? '#4B9E5F' : '#F1BF63'" |
|
|
|
|
> |
|
|
|
|
<template #title-right> |
|
|
|
|
<template v-if="env.VITE_APP_ENV == 'local'"> |
|
|
|
|
<template v-if="isBatchTransfer || isBatchUpgrade"> |
|
|
|
|
<el-button type="primary" @click="onBatchSave"> 确定{{ batchText }} </el-button> |
|
|
|
|
<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" /> |
|
|
|
|
{{ isonLineTransfer ? '数据迁移' : '数据导出' }} </el-button> |
|
|
|
|
<el-button v-if="isonLineTransfer" type="primary" @click="onBatchUpgrade"> <i |
|
|
|
|
class="i-codicon:chip mr-1" />批量升级 |
|
|
|
|
<el-button type="primary" @click="onBatchTransfer"> |
|
|
|
|
<i class="i-mdi:database-arrow-right-outline mr-1" /> |
|
|
|
|
{{ isonLineTransfer ? '数据迁移' : '数据导出' }} |
|
|
|
|
</el-button> |
|
|
|
|
<el-button v-if="isonLineTransfer" type="primary" @click="onBatchUpgrade"> |
|
|
|
|
<i class="i-codicon:chip mr-1" />批量升级 |
|
|
|
|
</el-button> |
|
|
|
|
</template> |
|
|
|
|
</template> |
|
|
|
@ -24,7 +33,10 @@
@@ -24,7 +33,10 @@
|
|
|
|
|
<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 !== '离线'"> |
|
|
|
|
<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"> |
|
|
|
@ -32,26 +44,38 @@
@@ -32,26 +44,38 @@
|
|
|
|
|
</div> |
|
|
|
|
</div> |
|
|
|
|
|
|
|
|
|
<div class="flex items-center gap-col-2" v-if="!(isBatchTransfer || isBatchUpgrade)"> |
|
|
|
|
<div |
|
|
|
|
class="flex items-center gap-col-2" |
|
|
|
|
v-if="!(isBatchTransfer || isBatchUpgrade)" |
|
|
|
|
> |
|
|
|
|
<template v-if="env.VITE_APP_ENV == 'local'"> |
|
|
|
|
<el-tooltip :content="isonLineTransfer ? '数据迁移' : '数据导出'" |
|
|
|
|
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 |
|
|
|
|
:content="isonLineTransfer ? '数据迁移' : '数据导出'" |
|
|
|
|
v-if="isonLineTransfer ? item.status === '在线' : true" |
|
|
|
|
> |
|
|
|
|
<i |
|
|
|
|
class="i-mdi:database-arrow-right-outline :hover:color-[#8ACE6A] color-[#4B9E5F] cursor-pointer text-20px" |
|
|
|
|
@click="onBatchTransferSave([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 |
|
|
|
|
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> |
|
|
|
|
</template> |
|
|
|
|
|
|
|
|
|
<el-tooltip content="详情"> |
|
|
|
|
<div |
|
|
|
|
class="i-material-symbols:info-outline :hover:color-[#8ACE6A] color-[#4B9E5F] cursor-pointer text-20px" |
|
|
|
|
@click="onDeviceDetails(item)"></div> |
|
|
|
|
@click="onDeviceDetails(item)" |
|
|
|
|
></div> |
|
|
|
|
</el-tooltip> |
|
|
|
|
</div> |
|
|
|
|
|
|
|
|
|
</div> |
|
|
|
|
|
|
|
|
|
<div class="device-item-body relative"> |
|
|
|
@ -85,168 +109,45 @@
@@ -85,168 +109,45 @@
|
|
|
|
|
</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', 'sc'].includes(item.upFirmware) || |
|
|
|
|
(item.upFirmwareStatus?.step === 4 && item.upFirmwareStatus?.progress === 100)" |
|
|
|
|
@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 === 4 && item.upFirmwareStatus?.progress === 100 ? '安装完成' : |
|
|
|
|
upgradeProgressStatusMap.find(r => r.status === item.upFirmwareStatus?.step)?.text ?? |
|
|
|
|
'--'}} |
|
|
|
|
</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" ref="transferLogScrollbar"> |
|
|
|
|
<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' || !onOffDeviceTransferStatus" |
|
|
|
|
:striped-flow="onOffDeviceTransferStatus === 'progress' || !onOffDeviceTransferStatus" :duration="20"> |
|
|
|
|
|
|
|
|
|
<div class="text-16px font-500"> {{ !!onOffDeviceTransferStatus ? onOffDeviceTransferStatus === |
|
|
|
|
'progress' |
|
|
|
|
? '数据导入中' : `数据导入完成 (失败:${offLineTransferRes().error}个 超时:${offLineTransferRes().timeout}个) ` : |
|
|
|
|
'数据导入中' |
|
|
|
|
}}</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" ref="transferLogScrollbar"> |
|
|
|
|
<div v-for="i in siteTransferLogList" |
|
|
|
|
:class="['error', 'timeout'].includes(i.status) ? '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" /> |
|
|
|
|
<OnLineTransferDlg |
|
|
|
|
ref="onLineTransferDlgRef" |
|
|
|
|
@on-save="onLineDeviceTransfer" |
|
|
|
|
:is-batch-transfer="isBatchTransfer" |
|
|
|
|
/> |
|
|
|
|
<OffTransferDlg |
|
|
|
|
ref="offTransferDlgRef" |
|
|
|
|
: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 type { IOfflineDevice, IOnlineDevice } 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' |
|
|
|
|
import { createTask, type TaskCreateParams } from '@/api/module/taks' |
|
|
|
|
const env = import.meta.env |
|
|
|
|
const onLineTransferDlgRef = ref<typeof OnLineTransferDlg>() |
|
|
|
|
const router = useRouter() |
|
|
|
@ -254,181 +155,30 @@ const route = useRoute()
@@ -254,181 +155,30 @@ 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 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: '迁移超时', |
|
|
|
|
stop: '迁移已终止', |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
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' | 'stop' | undefined>() |
|
|
|
|
const transferStatus = ref< |
|
|
|
|
'progress' | 'success' | 'failed' | 'timeout' | 'stop' | undefined |
|
|
|
|
>() |
|
|
|
|
|
|
|
|
|
const devices = computed(() => { |
|
|
|
|
return isonLineTransfer.value ? Array.from(devicesMap.value.values()) : offLineDeviceList.value |
|
|
|
|
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) |
|
|
|
|
|
|
|
|
|
// 在线设备批量迁移 |
|
|
|
|
function onLineDeviceTransfer() { |
|
|
|
|
if (isBatchTransfer.value) { |
|
|
|
|
onBatchCancel() |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
const statusMap = { |
|
|
|
|
200: 'success', |
|
|
|
|
1002: 'padding', |
|
|
|
|
1003: 'failed', |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const zmqExportMSG = ref('') |
|
|
|
|
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' |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const isLineFeed = feedback[2] && feedback[2].includes('\n') |
|
|
|
|
if (isLineFeed) { |
|
|
|
|
if (zmqExportMSG.value) { |
|
|
|
|
curTransferLog.value.at(-1)!.msg += feedback[2] |
|
|
|
|
} else { |
|
|
|
|
curTransferLog.value.push({ |
|
|
|
|
msg: `主机【${feedback[0]}】: ${feedback[2]}`, |
|
|
|
|
host: feedback[0], |
|
|
|
|
status, |
|
|
|
|
}) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
zmqExportMSG.value = '' |
|
|
|
|
} else { |
|
|
|
|
if (!zmqExportMSG.value) { |
|
|
|
|
curTransferLog.value.push({ |
|
|
|
|
msg: `主机【${feedback[0]}】: ${zmqExportMSG.value + feedback[2]}`, |
|
|
|
|
host: feedback[0], |
|
|
|
|
status, |
|
|
|
|
}) |
|
|
|
|
} |
|
|
|
|
zmqExportMSG.value += typeof feedback[2] === 'string' ? feedback : '' |
|
|
|
|
curTransferLog.value.at(-1)!.msg = zmqExportMSG.value |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
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) |
|
|
|
|
zmqExportMSG.value = '' |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
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() |
|
|
|
|
transferStatus.value = 'stop' |
|
|
|
|
}) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function zmqTimeoutCb(msg: TimeoutMsg) { |
|
|
|
|
const { device, action } = exportPubDeviceMap.get(msg.timeoutId)! |
|
|
|
|
if (device && action === 'export') { |
|
|
|
|
message.error(`迁移超时,请重新稍后尝试`) |
|
|
|
|
exportPubDeviceMap.delete(msg.timeoutId) |
|
|
|
|
closeTransferMask() |
|
|
|
|
transferStatus.value === 'failed' |
|
|
|
|
zmqExportMSG.value = '' |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
const onlineDeviceMap: Record< |
|
|
|
|
keyof Omit< |
|
|
|
|
IOnlineDevice, |
|
|
|
@ -460,16 +210,38 @@ function onBatchTransfer() {
@@ -460,16 +210,38 @@ function onBatchTransfer() {
|
|
|
|
|
|
|
|
|
|
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?.site_id}/${item?.sn}`) |
|
|
|
|
.filter(Boolean) |
|
|
|
|
.join(',') |
|
|
|
|
|
|
|
|
|
onLineTransferDlgRef.value?.open(checkList[0], clientIpList, pathList) |
|
|
|
|
const lineDevices = checkDeviceList as IOnlineDevice[] |
|
|
|
|
const site = lineDevices[0]?.site_id |
|
|
|
|
if (!site) { |
|
|
|
|
message.error('请选择站点') |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
const deivcesParms = lineDevices.map(item => ({ |
|
|
|
|
sn: item.sn, |
|
|
|
|
host: item.clientIp, |
|
|
|
|
disk: item.footprint, |
|
|
|
|
})) |
|
|
|
|
|
|
|
|
|
const parmas: TaskCreateParams = { |
|
|
|
|
site, |
|
|
|
|
devices: deivcesParms, |
|
|
|
|
mode: 'export', |
|
|
|
|
} |
|
|
|
|
onLineTransferDlgRef.value?.open(parmas) |
|
|
|
|
} else { |
|
|
|
|
offTransferDlg.value?.open(checkDeviceList, true) |
|
|
|
|
const offlineDevices = checkDeviceList as IOfflineDevice[] |
|
|
|
|
const site = offlineDevices[0]?.site_id |
|
|
|
|
const deivcesParms = offlineDevices.map(item => ({ |
|
|
|
|
sn: item.sn, |
|
|
|
|
})) |
|
|
|
|
|
|
|
|
|
const parmas: TaskCreateParams = { |
|
|
|
|
site, |
|
|
|
|
devices: deivcesParms, |
|
|
|
|
mode: 'import', |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
offTransferDlgRef.value?.open(parmas) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -511,9 +283,7 @@ function getOnlineDeviceList(): IOnlineDevice[] {
@@ -511,9 +283,7 @@ function getOnlineDeviceList(): IOnlineDevice[] {
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
function getOfflineDeviceList(): IOfflineDevice[] { |
|
|
|
|
return offLineDeviceList.value.filter(item => |
|
|
|
|
checkDeviceList.value.includes(item.sn) |
|
|
|
|
) |
|
|
|
|
return offLineDeviceList.value.filter(item => checkDeviceList.value.includes(item.sn)) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
function onBatchCancel() { |
|
|
|
@ -521,13 +291,6 @@ function onBatchCancel() {
@@ -521,13 +291,6 @@ function onBatchCancel() {
|
|
|
|
|
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') |
|
|
|
@ -583,202 +346,43 @@ function onDeviceDetails(item: IOfflineDevice) {
@@ -583,202 +346,43 @@ function onDeviceDetails(item: IOfflineDevice) {
|
|
|
|
|
const isCanFirmwareUpload = computed(() => !!firmwarePath.value && isonLineTransfer.value) |
|
|
|
|
|
|
|
|
|
const upgradeSnList = ref<string[]>([]) |
|
|
|
|
const upgradePubDeviceMap = new Map<string, UpFirmwarsDevice>() |
|
|
|
|
function onFirmwareUpload(devices: IOnlineDevice[]) { |
|
|
|
|
async 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.code |
|
|
|
|
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 === ZmqMsgResultType.PROGRESS) { |
|
|
|
|
upFirmwareStatus(deviceSn, msg.feedback) |
|
|
|
|
if (progressStatus === 4 && progress === 100) { |
|
|
|
|
upFirmwareSucceed(deviceSn) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
if (status === ZmqMsgResultType.SUCCESS || status === ZmqMsgResultType.ERROR) { |
|
|
|
|
upFirmwareStatus(deviceSn, msg.feedback) |
|
|
|
|
if (status === ZmqMsgResultType.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' |
|
|
|
|
const site = devices[0]?.site_id |
|
|
|
|
if (!site) { |
|
|
|
|
message.error('请选择站点') |
|
|
|
|
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 offLineTransferRes = () => { |
|
|
|
|
let timeoutNum = 0 |
|
|
|
|
let errorNum = 0 |
|
|
|
|
|
|
|
|
|
const findTimeout = siteTransferLogList.value.filter(i => i.status === 'timeout') |
|
|
|
|
const uniqueTimeoutSn = new Set(findTimeout.map(i => i.device.sn)) |
|
|
|
|
|
|
|
|
|
timeoutNum = uniqueTimeoutSn.size |
|
|
|
|
const findError = siteTransferLogList.value.filter(i => i.status === 'error') |
|
|
|
|
errorNum = new Set(findError.map(i => i.device.sn)).size |
|
|
|
|
|
|
|
|
|
return { |
|
|
|
|
timeout: timeoutNum, |
|
|
|
|
error: errorNum, |
|
|
|
|
const deivcesParms = devices.map(item => ({ |
|
|
|
|
sn: item.sn, |
|
|
|
|
host: item.clientIp, |
|
|
|
|
disk: item.footprint, |
|
|
|
|
})) |
|
|
|
|
|
|
|
|
|
const parmas: TaskCreateParams = { |
|
|
|
|
site, |
|
|
|
|
devices: deivcesParms, |
|
|
|
|
mode: 'update', |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
const importMsg = ref('') |
|
|
|
|
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] || '' : '' |
|
|
|
|
const isLineFeed = log && log.includes('\n') |
|
|
|
|
if (isLineFeed) { |
|
|
|
|
if (importMsg.value) { |
|
|
|
|
siteTransferLogList.value.at(-1)!.msg += log |
|
|
|
|
} else { |
|
|
|
|
siteTransferLogList.value.push({ |
|
|
|
|
msg: log, |
|
|
|
|
device: offDevice, |
|
|
|
|
status: 'success' |
|
|
|
|
}) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
importMsg.value = '' |
|
|
|
|
} else { |
|
|
|
|
if (!importMsg.value) { |
|
|
|
|
siteTransferLogList.value.push({ |
|
|
|
|
msg: log, |
|
|
|
|
device: offDevice, |
|
|
|
|
status: 'success' |
|
|
|
|
}) |
|
|
|
|
} |
|
|
|
|
importMsg.value += typeof log === 'string' ? log : '' |
|
|
|
|
siteTransferLogList.value.at(-1)!.msg = importMsg.value |
|
|
|
|
} |
|
|
|
|
const res = await createTask(parmas) |
|
|
|
|
if (res.code !== 0) { |
|
|
|
|
message.error(`任务创建失败`) |
|
|
|
|
} else { |
|
|
|
|
message.success('任务创建成功,请在任务列表中查看') |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (code !== ZmqMsgResultType.PROGRESS) { |
|
|
|
|
importQueue.value.shift() |
|
|
|
|
isImporting.value = false |
|
|
|
|
if (code === ZmqMsgResultType.ERROR) { |
|
|
|
|
siteTransferLogList.value.push({ |
|
|
|
|
msg: `数据导入失败,请稍后重试消息结果:${result}`, |
|
|
|
|
device: offDevice, |
|
|
|
|
status: 'error' |
|
|
|
|
}) |
|
|
|
|
} |
|
|
|
|
importMsg.value = '' |
|
|
|
|
processNextImport() |
|
|
|
|
} |
|
|
|
|
onBatchCancel() |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
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: 'timeout' |
|
|
|
|
}) |
|
|
|
|
importQueue.value.shift() |
|
|
|
|
isImporting.value = false |
|
|
|
|
importMsg.value = '' |
|
|
|
|
processNextImport() |
|
|
|
|
} |
|
|
|
|
// ================ 离线数据导入 ========= |
|
|
|
|
const offTransferDlgRef = ref<typeof OffTransferDlg>() |
|
|
|
|
function onOffDeviceTransfer() { |
|
|
|
|
onBatchCancel() |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// ================ 离线数据导入 end ========= |
|
|
|
|