Browse Source

feat: 前端兼容本地数据批量导出

main
betaqi 2 months ago
parent
commit
3e49830817
  1. 6
      src/utils/zmq.ts
  2. 41
      src/views/stationData/components/offTransferDlg.vue
  3. 3
      src/views/stationData/index.vue
  4. 188
      src/views/stationData/transferData.vue

6
src/utils/zmq.ts

@ -14,6 +14,12 @@ export enum WorkerCMD {
SET_TIMEOUT SET_TIMEOUT
} }
export enum ZmqMsgResultType {
SUCCESS = 200,
PROGRESS = 1002,
ERROR = 1003,
}
export enum ZmqCMD { export enum ZmqCMD {
MSG, MSG,

41
src/views/stationData/components/offTransferDlg.vue

@ -23,7 +23,7 @@ const message = useMessage()
const emit = defineEmits<{ const emit = defineEmits<{
'on-save': [msg: PublishMsg<'import'>, site: IOfflineDevice] 'on-save': [msg: PublishMsg<'import'>[], site: IOfflineDevice[]]
}>() }>()
const props = defineProps<{ const props = defineProps<{
@ -36,41 +36,48 @@ const fromData = {
clientIp: '', clientIp: '',
} }
const curOffDeive = ref<IOfflineDevice>() const curOffDeive = ref<IOfflineDevice[]>([])
const form = ref(cloneDeep(fromData)) const form = ref(cloneDeep(fromData))
const isBatchTransfer = ref(false)
function open(item: IOfflineDevice[], isBatch: boolean = false) {
function open(item: IOfflineDevice) {
curOffDeive.value = item curOffDeive.value = item
visible.value = true visible.value = true
isBatchTransfer.value = isBatch
} }
function onSave() { function onSave() {
if (verifyData()) return if (verifyData()) return
if (!curOffDeive.value) { if (!curOffDeive.value.length) {
message.error('请选择设备') message.error('请选择设备')
return return
} }
const params = [ const msgList: PublishMsg<"import">[] = []
`${form.value.clientIp}`, for (const device of curOffDeive.value) {
'', const params = [
'', `${form.value.clientIp}`,
'', '',
'', '',
'', '',
`${props.siteInfo!.name}/${curOffDeive.value.sn}`, '',
] '',
const msg = getPubInitData<'import'>('import', params) `${props.siteInfo!.name}/${device.sn}`,
emit('on-save', msg, curOffDeive.value) ]
const msg = getPubInitData<'import'>('import', params)
msgList.push(msg)
}
emit('on-save', msgList, curOffDeive.value)
close() close()
} }
function close() { function close() {
form.value = cloneDeep(fromData) form.value = cloneDeep(fromData)
curOffDeive.value = undefined curOffDeive.value = []
visible.value = false visible.value = false
isBatchTransfer.value = false
} }
const ipPattern = const ipPattern =
/^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/ /^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/

3
src/views/stationData/index.vue

@ -110,9 +110,6 @@ function onSiteDetails(site: ISite) {
}) })
} }
const isSiteTransfer = ref(false)
const transferLoading = ref(false)
const siteList = ref<ISite[]>([]) const siteList = ref<ISite[]>([])
async function loadSiteList() { async function loadSiteList() {
const res = await getSiteList() const res = await getSiteList()

188
src/views/stationData/transferData.vue

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

Loading…
Cancel
Save