|
|
|
@ -12,12 +12,13 @@
@@ -12,12 +12,13 @@
|
|
|
|
|
<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="isTransfer" type="primary" @click="onBatchUpgrade"> <i class="i-codicon:chip mr-1" />批量升级 |
|
|
|
|
<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="onlineDeviceCheckList"> |
|
|
|
|
<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"> |
|
|
|
@ -29,11 +30,11 @@
@@ -29,11 +30,11 @@
|
|
|
|
|
</div> |
|
|
|
|
</div> |
|
|
|
|
<div class="flex items-center gap-col-2" v-if="!(isBatchTransfer || isBatchUpgrade)"> |
|
|
|
|
<el-tooltip content="数据迁移" v-if="isTransfer ? item.status === '在线' : true"> |
|
|
|
|
<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="isTransfer && item.status === '在线'"> |
|
|
|
|
<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> |
|
|
|
@ -46,9 +47,9 @@
@@ -46,9 +47,9 @@
|
|
|
|
|
</div> |
|
|
|
|
|
|
|
|
|
<div class="device-item-body relative"> |
|
|
|
|
<template v-if="isTransfer"> |
|
|
|
|
<template v-if="isonLineTransfer"> |
|
|
|
|
<template v-for="key in Object.keys(onlineDeviceMap)"> |
|
|
|
|
<div class="info-item" v-if="isTransfer && key === 'status'"> |
|
|
|
|
<div class="info-item" v-if="isonLineTransfer && key === 'status'"> |
|
|
|
|
<div>{{ onlineDeviceMap.status }}:</div> |
|
|
|
|
<el-tag :type="item.status === '在线' ? 'success' : 'danger'"> |
|
|
|
|
{{ item.status }} |
|
|
|
@ -168,17 +169,21 @@
@@ -168,17 +169,21 @@
|
|
|
|
|
" class="flex-1" :stroke-width="18" :text-inside="true" |
|
|
|
|
:striped="onOffDeviceTransferStatus === 'progress'" |
|
|
|
|
:striped-flow="onOffDeviceTransferStatus === 'progress'" :duration="20"> |
|
|
|
|
<div class="text-16px font-500">{{ transferStatusMap[onOffDeviceTransferStatus as keyof typeof |
|
|
|
|
transferStatusMap] |
|
|
|
|
?? |
|
|
|
|
'' }}</div> |
|
|
|
|
|
|
|
|
|
<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"> {{ i }} </div> |
|
|
|
|
<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> |
|
|
|
@ -190,7 +195,7 @@
@@ -190,7 +195,7 @@
|
|
|
|
|
|
|
|
|
|
<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="isTransfer" /> |
|
|
|
|
<DeviceDrawer v-model="isShowDetails" ref="deviceDrawerRef" :siteInfo="siteInfo" :is-transfer="isonLineTransfer" /> |
|
|
|
|
</template> |
|
|
|
|
|
|
|
|
|
<script setup lang="ts"> |
|
|
|
@ -202,6 +207,7 @@ import OffTransferDlg from './components/offTransferDlg.vue'
@@ -202,6 +207,7 @@ import OffTransferDlg from './components/offTransferDlg.vue'
|
|
|
|
|
|
|
|
|
|
import { |
|
|
|
|
getPubInitData, |
|
|
|
|
ZmqMsgResultType, |
|
|
|
|
type PublishMsg, |
|
|
|
|
type PubMsgData, |
|
|
|
|
type TimeoutMsg, |
|
|
|
@ -234,7 +240,7 @@ const siteInfo = ref<ISite>(
@@ -234,7 +240,7 @@ const siteInfo = ref<ISite>(
|
|
|
|
|
) |
|
|
|
|
const type = ref<'export' | 'details'>(route.query.type as 'export' | 'details') |
|
|
|
|
|
|
|
|
|
const isTransfer = computed(() => type.value === 'export') |
|
|
|
|
const isonLineTransfer = computed(() => type.value === 'export') |
|
|
|
|
|
|
|
|
|
const isShowTransferMask = ref(false) |
|
|
|
|
|
|
|
|
@ -263,7 +269,7 @@ const curTransferLog = ref<
@@ -263,7 +269,7 @@ const curTransferLog = ref<
|
|
|
|
|
const transferStatus = ref<'progress' | 'success' | 'failed' | 'timeout' | undefined>() |
|
|
|
|
|
|
|
|
|
const devices = computed(() => { |
|
|
|
|
return isTransfer.value ? Array.from(devicesMap.value.values()) : deviceList.value |
|
|
|
|
return isonLineTransfer.value ? Array.from(devicesMap.value.values()) : offLineDeviceList.value |
|
|
|
|
}) as Ref<any[]> |
|
|
|
|
|
|
|
|
|
const transferLoading = ref(false) |
|
|
|
@ -306,7 +312,7 @@ const statusMap = {
@@ -306,7 +312,7 @@ const statusMap = {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function zmqExportCb(msg: PubMsgData) { |
|
|
|
|
if (!isTransfer.value) return |
|
|
|
|
if (!isonLineTransfer.value) return |
|
|
|
|
const { feedback, result, id } = msg |
|
|
|
|
transferLoading.value = false |
|
|
|
|
if (feedback && feedback[0]) { |
|
|
|
@ -400,27 +406,32 @@ const offlineDeviceMap: Record<
@@ -400,27 +406,32 @@ const offlineDeviceMap: Record<
|
|
|
|
|
create_time: '创建时间', |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
const onlineDeviceCheckList = ref<string[]>([]) |
|
|
|
|
const checkDeviceList = ref<string[]>([]) |
|
|
|
|
|
|
|
|
|
const isBatchTransfer = ref(false) |
|
|
|
|
function onBatchTransfer() { |
|
|
|
|
onlineDeviceCheckList.value = [] |
|
|
|
|
checkDeviceList.value = [] |
|
|
|
|
isBatchTransfer.value = true |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
function onBatchTransferSave(checkList: IOnlineDevice[]) { |
|
|
|
|
const clientIpList = checkList.map(item => item?.clientIp).join(',') |
|
|
|
|
const pathList = checkList |
|
|
|
|
.map(item => `${item?.stationName}/${item?.sn}`) |
|
|
|
|
.filter(Boolean) |
|
|
|
|
.join(',') |
|
|
|
|
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) |
|
|
|
|
onLineTransferDlgRef.value?.open(checkList[0], clientIpList, pathList) |
|
|
|
|
} else { |
|
|
|
|
offTransferDlg.value?.open(checkDeviceList, true) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
const isBatchUpgrade = ref(false) |
|
|
|
|
function onBatchUpgrade() { |
|
|
|
|
onlineDeviceCheckList.value = [] |
|
|
|
|
checkDeviceList.value = [] |
|
|
|
|
isBatchUpgrade.value = true |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -429,33 +440,48 @@ const batchText = computed(() => {
@@ -429,33 +440,48 @@ const batchText = computed(() => {
|
|
|
|
|
}) |
|
|
|
|
|
|
|
|
|
function onBatchSave() { |
|
|
|
|
if (!onlineDeviceCheckList.value.length) { |
|
|
|
|
if (!checkDeviceList.value.length) { |
|
|
|
|
message.error(`请选择要${batchText.value}的设备`) |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
const checkList = onlineDeviceCheckList.value |
|
|
|
|
.map(sn => { |
|
|
|
|
return devicesMap.value.get(sn) ?? undefined |
|
|
|
|
}) |
|
|
|
|
.filter(Boolean) as IOnlineDevice[] |
|
|
|
|
|
|
|
|
|
const checkList = isonLineTransfer.value |
|
|
|
|
? getOnlineDeviceList() |
|
|
|
|
: getOfflineDeviceList() |
|
|
|
|
|
|
|
|
|
if (isBatchTransfer.value) { |
|
|
|
|
onBatchTransferSave(checkList) |
|
|
|
|
} |
|
|
|
|
if (isBatchUpgrade.value) { |
|
|
|
|
onFirmwareUpload(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 |
|
|
|
|
onlineDeviceCheckList.value = [] |
|
|
|
|
checkDeviceList.value = [] |
|
|
|
|
} |
|
|
|
|
function onTransfer(item: IOnlineDevice) { |
|
|
|
|
if (isTransfer.value) { |
|
|
|
|
if (isonLineTransfer.value) { |
|
|
|
|
onLineTransferDlgRef.value?.open(item) |
|
|
|
|
} else { |
|
|
|
|
offTransferDlg.value?.open(item) |
|
|
|
|
offTransferDlg.value?.open([item]) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -481,19 +507,19 @@ onBeforeRouteLeave(async (to, from, next) => {
@@ -481,19 +507,19 @@ onBeforeRouteLeave(async (to, from, next) => {
|
|
|
|
|
} |
|
|
|
|
}) |
|
|
|
|
|
|
|
|
|
const deviceList = ref<IOfflineDevice[]>([]) |
|
|
|
|
const offLineDeviceList = ref<IOfflineDevice[]>([]) |
|
|
|
|
|
|
|
|
|
async function loadDeviceList() { |
|
|
|
|
const res = await getDeviceList(siteInfo.value.name) |
|
|
|
|
if (res.code === 200 || res.code === 0) { |
|
|
|
|
deviceList.value = res.data |
|
|
|
|
offLineDeviceList.value = res.data |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
const firmwarePath = ref('') |
|
|
|
|
|
|
|
|
|
onMounted(async () => { |
|
|
|
|
if (!isTransfer.value) { |
|
|
|
|
if (!isonLineTransfer.value) { |
|
|
|
|
loadDeviceList() |
|
|
|
|
} else { |
|
|
|
|
const res = await getFirmwarePath() |
|
|
|
@ -510,7 +536,7 @@ function onDeviceDetails(item: IOfflineDevice) {
@@ -510,7 +536,7 @@ function onDeviceDetails(item: IOfflineDevice) {
|
|
|
|
|
deviceDrawerRef.value?.open(item) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
const isCanFirmwareUpload = computed(() => !!firmwarePath.value && isTransfer.value) |
|
|
|
|
const isCanFirmwareUpload = computed(() => !!firmwarePath.value && isonLineTransfer.value) |
|
|
|
|
|
|
|
|
|
const upgradeSnList = ref<string[]>([]) |
|
|
|
|
const upgradePubDeviceMap = new Map<string, UpFirmwarsDevice>() |
|
|
|
@ -559,7 +585,7 @@ function firmwareUpTimeoutCb(msg: TimeoutMsg) {
@@ -559,7 +585,7 @@ function firmwareUpTimeoutCb(msg: TimeoutMsg) {
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
function zmqUpgradeCb(msg: PubMsgData) { |
|
|
|
|
if (!isTransfer.value) return |
|
|
|
|
if (!isonLineTransfer.value) return |
|
|
|
|
const status = msg.result |
|
|
|
|
const deviceSn = msg.feedback[0] |
|
|
|
|
const progressStatus = msg.feedback[1] as number |
|
|
|
@ -590,36 +616,71 @@ function zmqUpgradeCb(msg: PubMsgData) {
@@ -590,36 +616,71 @@ function zmqUpgradeCb(msg: PubMsgData) {
|
|
|
|
|
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] |
|
|
|
|
|
|
|
|
|
function onOffDeviceTransfer(msg: PublishMsg<'import'>, offDevice: IOfflineDevice) { |
|
|
|
|
pubIdWithOffDevice.set(msg.id, { offDevice, action: 'import' }) |
|
|
|
|
worker.publish(postTransferTopic, msg, true, zmqImportTimeoutCb) |
|
|
|
|
worker.subscribe(getTransferTopic, zmqImportCb, msg.id) |
|
|
|
|
openTransferMask('import') |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
const siteTransferLogList = ref<string[]>([]) |
|
|
|
|
function onOffDeviceTransfer(msg: PublishMsg<'import'>[], offDevice: IOfflineDevice[]) { |
|
|
|
|
// 将设备和消息添加到队列中 |
|
|
|
|
msg.forEach((m, index) => { |
|
|
|
|
importQueue.value.push({ msg: m, offDevice: offDevice[index] }) |
|
|
|
|
}) |
|
|
|
|
|
|
|
|
|
const onOffDeviceTransferStatus = ref<'progress' | 'success' | 'failed' | 'timeout' | undefined>() |
|
|
|
|
// 开始处理队列 |
|
|
|
|
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, result, feedback } = msg |
|
|
|
|
const { id, feedback, result, code } = msg |
|
|
|
|
transferLoading.value = false |
|
|
|
|
const { offDevice, action } = pubIdWithOffDevice.get(id)! |
|
|
|
|
if (action !== 'import' || !offDevice) return |
|
|
|
|
transferLoading.value = false |
|
|
|
|
if (result === 'progress') { |
|
|
|
|
if (code === ZmqMsgResultType.PROGRESS) { |
|
|
|
|
onOffDeviceTransferStatus.value = 'progress' |
|
|
|
|
const log: string = Array.isArray(feedback) ? feedback[0] || '' : '' |
|
|
|
|
siteTransferLogList.value.push(log) |
|
|
|
|
siteTransferLogList.value.push({ |
|
|
|
|
msg: log, |
|
|
|
|
device: offDevice, |
|
|
|
|
status: 'success' |
|
|
|
|
}) |
|
|
|
|
} |
|
|
|
|
if (result !== 'progress') { |
|
|
|
|
if (result === 'success') { |
|
|
|
|
onOffDeviceTransferStatus.value = 'success' |
|
|
|
|
message.success(`导出数据成功`) |
|
|
|
|
} else { |
|
|
|
|
onOffDeviceTransferStatus.value = 'failed' |
|
|
|
|
message.error(`导出数据失败`) |
|
|
|
|
|
|
|
|
|
if (code !== ZmqMsgResultType.PROGRESS) { |
|
|
|
|
// 从队列中移除已处理的消息 |
|
|
|
|
importQueue.value.shift() |
|
|
|
|
isImporting.value = false |
|
|
|
|
if (code === ZmqMsgResultType.ERROR) { |
|
|
|
|
siteTransferLogList.value.push({ |
|
|
|
|
msg: `数据导入失败,请稍后重试消息结果:${result}`, |
|
|
|
|
device: offDevice, |
|
|
|
|
status: 'error' |
|
|
|
|
}) |
|
|
|
|
} |
|
|
|
|
// 处理队列中的下一个消息 |
|
|
|
|
processNextImport() |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -627,9 +688,20 @@ function zmqImportTimeoutCb(msg: TimeoutMsg) {
@@ -627,9 +688,20 @@ 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) |
|
|
|
|
onOffDeviceTransferStatus.value = 'timeout' |
|
|
|
|
closeTransferMask() |
|
|
|
|
siteTransferLogList.value.push({ |
|
|
|
|
msg: `数据导入超时,请稍后重试`, |
|
|
|
|
device: offDevice, |
|
|
|
|
status: 'error' |
|
|
|
|
}) |
|
|
|
|
// 从队列中移除超时的项目 |
|
|
|
|
importQueue.value.shift() |
|
|
|
|
isImporting.value = false |
|
|
|
|
|
|
|
|
|
// 处理队列中的下一个项目 |
|
|
|
|
processNextImport() |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|