feat(ota): support JSON progress updates
This commit is contained in:
@@ -1,17 +1,20 @@
|
||||
import type { DeviceFirmwareStatus } from '@/services/device'
|
||||
import { isFirmwareCurrent, isFirmwareTargetReached, isFirmwareUpdateInProgress } from '../../utils/firmware-status'
|
||||
import { isFirmwareCurrent, isFirmwareTargetReached, isFirmwareUpdateInProgress, normalizeFirmwareStatus } from '../../utils/firmware-status'
|
||||
|
||||
export function firmwareProgressView(status: DeviceFirmwareStatus | null, refreshError = false) {
|
||||
const state = String(status?.update_status || '').trim().toLowerCase()
|
||||
const normalizedStatus = normalizeFirmwareStatus(status)
|
||||
const state = String(normalizedStatus?.update_status || '').trim().toLowerCase()
|
||||
const complete = state === 'success' || state === 'completed'
|
||||
|| (isFirmwareUpdateInProgress(state) && isFirmwareTargetReached(status))
|
||||
const current = !complete && !isFirmwareUpdateInProgress(state) && isFirmwareCurrent(status)
|
||||
|| (isFirmwareUpdateInProgress(state) && isFirmwareTargetReached(normalizedStatus))
|
||||
const current = !complete && !isFirmwareUpdateInProgress(state) && isFirmwareCurrent(normalizedStatus)
|
||||
const failed = state === 'failed' && !current
|
||||
const value = Number(status?.progress)
|
||||
const value = Number(normalizedStatus?.progress)
|
||||
const progress = complete ? 100 : Number.isFinite(value) ? Math.max(0, Math.min(100, value)) : 0
|
||||
const hasProgress = complete || progress > 0
|
||||
const target = status?.target_version
|
||||
const version = current ? status?.current_version : target && !['unknown', 'updating'].includes(target) ? target : status?.latest_version
|
||||
// MQTT 003 carries target_version; latest_version is display-only fallback
|
||||
// for older status rows and must not be used for completion detection.
|
||||
const target = normalizedStatus?.target_version
|
||||
const version = current ? normalizedStatus?.current_version : target && !['unknown', 'updating'].includes(target) ? target : normalizedStatus?.latest_version
|
||||
const title = complete ? '固件更新完成' : current ? '当前已是最新版本' : failed ? '固件更新失败' : '固件更新中'
|
||||
const message = complete ? '设备已完成更新,可以继续使用。'
|
||||
: current ? '当前设备已运行最新版本,无需更新。'
|
||||
|
||||
@@ -8,6 +8,20 @@ export function isFirmwareUpdateInProgress(status?: string | null): boolean {
|
||||
return ['sent', 'accepted', 'updating'].includes(normalizeFirmwareUpdateStatus(status))
|
||||
}
|
||||
|
||||
export function normalizeFirmwareStatus(status: DeviceFirmwareStatus | null): DeviceFirmwareStatus | null {
|
||||
if (!status) return null
|
||||
|
||||
const numericProgress = Number(status.progress)
|
||||
const progress = Number.isFinite(numericProgress)
|
||||
? Math.max(0, Math.min(100, numericProgress))
|
||||
: 0
|
||||
|
||||
return {
|
||||
...status,
|
||||
progress,
|
||||
}
|
||||
}
|
||||
|
||||
function firmwareVersionParts(value?: string | null): number[] | null {
|
||||
const normalized = String(value || '').trim().toLowerCase()
|
||||
if (!normalized || ['unknown', 'updating', '0.0.0', '--'].includes(normalized)) return null
|
||||
@@ -36,15 +50,16 @@ export function isFirmwareCurrent(status: DeviceFirmwareStatus | null): boolean
|
||||
}
|
||||
|
||||
export function firmwareSummaryView(status: DeviceFirmwareStatus | null) {
|
||||
if (!status) return { action: '暂不可用', subtitle: '暂时无法获取版本,请稍后重试' }
|
||||
if (isFirmwareUpdateInProgress(status.update_status) && !isFirmwareTargetReached(status)) {
|
||||
const normalizedStatus = normalizeFirmwareStatus(status)
|
||||
if (!normalizedStatus) return { action: '暂不可用', subtitle: '暂时无法获取版本,请稍后重试' }
|
||||
if (isFirmwareUpdateInProgress(normalizedStatus.update_status) && !isFirmwareTargetReached(normalizedStatus)) {
|
||||
return { action: '查看进度', subtitle: '设备正在更新,请稍候' }
|
||||
}
|
||||
if (isFirmwareCurrent(status)) return { action: '已最新', subtitle: '当前已是最新版本' }
|
||||
if (normalizeFirmwareUpdateStatus(status.update_status) === 'failed') {
|
||||
return { action: status.update_available ? '更新' : '版本待确认', subtitle: status.can_update ? '更新失败,可重试' : '上次更新失败,当前版本待确认' }
|
||||
if (isFirmwareCurrent(normalizedStatus)) return { action: '已最新', subtitle: '当前已是最新版本' }
|
||||
if (normalizeFirmwareUpdateStatus(normalizedStatus.update_status) === 'failed') {
|
||||
return { action: normalizedStatus.update_available ? '更新' : '版本待确认', subtitle: normalizedStatus.can_update ? '更新失败,可重试' : '上次更新失败,当前版本待确认' }
|
||||
}
|
||||
return status.update_available
|
||||
return normalizedStatus.update_available
|
||||
? { action: '更新', subtitle: '发现可更新版本' }
|
||||
: { action: '版本待确认', subtitle: '暂无完整版本信息' }
|
||||
}
|
||||
|
||||
@@ -32,6 +32,22 @@ test('received progress is used directly, including fractional values', () => {
|
||||
assert.equal(view.percent, 65)
|
||||
assert.equal(view.complete, false)
|
||||
})
|
||||
test('MQTT 003 target_version is shown while progress is updating', () => {
|
||||
const view = firmwareProgressView({
|
||||
...status('updating', 30),
|
||||
latest_version: '2.0.4',
|
||||
target_version: '2.0.4',
|
||||
})
|
||||
assert.equal(view.version, '2.0.4')
|
||||
assert.equal(view.progress, 30)
|
||||
assert.equal(view.percent, 30)
|
||||
assert.match(view.message, /保持设备电量充足/)
|
||||
})
|
||||
test('active status without target_version falls back to latest_version', () => {
|
||||
const view = firmwareProgressView(status('updating', 30))
|
||||
assert.equal(view.version, '1.8.2')
|
||||
assert.equal(view.progress, 30)
|
||||
})
|
||||
test('nearly complete progress never rounds up to 100', () => {
|
||||
assert.equal(firmwareProgressView(status('updating', 99.9)).percent, 99)
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user