224 lines
6.8 KiB
TypeScript
224 lines
6.8 KiB
TypeScript
import { onLoad } from '@dcloudio/uni-app'
|
|
import { computed, ref } from 'vue'
|
|
import { getErrorMessage } from '@/utils/api-error'
|
|
import { fetchDeviceList } from '../device.api'
|
|
import { fetchDeviceRuntime, updateDeviceRuntime } from './device-detail.api'
|
|
import type { AppDeviceRuntimeVo, DeviceDetailRouteQuery, FanLevel, RunMode } from './device-detail.types'
|
|
import {
|
|
AUTO_FAN_LEVEL_OPTIONS,
|
|
formatConnectionText,
|
|
formatPowerMode,
|
|
formatTvocLevel,
|
|
formatTvocValue,
|
|
isAutoRunMode,
|
|
isBluetoothConnected,
|
|
mapRuntimeToView,
|
|
RUN_MODE_OPTIONS,
|
|
} from './device-detail.utils'
|
|
import { useDeviceBluetoothSync } from './use-device-bluetooth-sync'
|
|
|
|
export function useDeviceDetail() {
|
|
const deviceId = ref(0)
|
|
const deviceMac = ref<string>()
|
|
const deviceName = ref('')
|
|
const locationName = ref('客厅')
|
|
const deviceStatus = ref<string>()
|
|
const bluetoothConnected = ref(false)
|
|
const charging = ref(false)
|
|
const isOnline = ref(false)
|
|
const loading = ref(false)
|
|
const updating = ref(false)
|
|
|
|
const runMode = ref<RunMode>('0')
|
|
const fanLevel = ref<FanLevel>('0')
|
|
const tvoc = ref<number | null>(null)
|
|
const powerMode = ref('0')
|
|
const filterLife = ref(0)
|
|
const filterRemainText = ref('预计还可使用 -- 天')
|
|
const filterReplaced = ref(false)
|
|
const filterReplaceDialogVisible = ref(false)
|
|
const batteryLevel = ref<number | null>(null)
|
|
const syncText = ref('数据实时同步中')
|
|
|
|
const tvocDisplay = computed(() => formatTvocValue(tvoc.value ?? undefined))
|
|
const tvocLevel = computed(() => formatTvocLevel(tvoc.value ?? undefined))
|
|
const powerModeText = computed(() => formatPowerMode(powerMode.value))
|
|
const batteryDisplay = computed(() =>
|
|
batteryLevel.value != null ? `${batteryLevel.value}%` : '--',
|
|
)
|
|
const connectionText = computed(() =>
|
|
formatConnectionText({
|
|
status: deviceStatus.value,
|
|
bluetoothConnected: bluetoothConnected.value ? '1' : '0',
|
|
locationName: locationName.value,
|
|
}),
|
|
)
|
|
const showFanLevelControl = computed(() => isAutoRunMode(runMode.value))
|
|
const fanLevelOptions = computed(() =>
|
|
showFanLevelControl.value ? AUTO_FAN_LEVEL_OPTIONS : [],
|
|
)
|
|
|
|
function applyRuntime(data: AppDeviceRuntimeVo) {
|
|
const view = mapRuntimeToView(data, deviceName.value)
|
|
deviceName.value = view.deviceName
|
|
runMode.value = view.runMode
|
|
fanLevel.value = view.fanLevel
|
|
tvoc.value = view.tvoc
|
|
powerMode.value = view.powerMode
|
|
filterLife.value = view.filterLife
|
|
filterRemainText.value = view.filterRemainText
|
|
filterReplaced.value = view.filterReplaced
|
|
isOnline.value = view.isOnline
|
|
if (data.status !== undefined) deviceStatus.value = data.status
|
|
syncText.value = '刚刚更新 · 数据实时同步中'
|
|
}
|
|
|
|
async function refreshDeviceMeta() {
|
|
if (!deviceId.value) return
|
|
try {
|
|
const list = await fetchDeviceList()
|
|
const device = list?.find((item) => item.deviceId === deviceId.value)
|
|
if (!device) return
|
|
if (device.mac) deviceMac.value = device.mac
|
|
bluetoothConnected.value = isBluetoothConnected(device.bluetoothConnected)
|
|
charging.value = device.charging === '1'
|
|
if (device.status !== undefined) deviceStatus.value = device.status
|
|
isOnline.value = device.status === '1'
|
|
} catch {
|
|
// 列表刷新失败时保留路由参数状态
|
|
}
|
|
}
|
|
|
|
async function loadRuntime() {
|
|
if (!deviceId.value) return
|
|
loading.value = true
|
|
try {
|
|
const [runtime] = await Promise.all([
|
|
fetchDeviceRuntime({ deviceId: deviceId.value }),
|
|
refreshDeviceMeta(),
|
|
])
|
|
applyRuntime(runtime)
|
|
} catch (err) {
|
|
uni.showToast({ title: getErrorMessage(err, '加载设备数据失败'), icon: 'none' })
|
|
} finally {
|
|
loading.value = false
|
|
}
|
|
}
|
|
|
|
async function patchRuntime(patch: { runMode?: RunMode; fanLevel?: FanLevel }) {
|
|
if (!deviceId.value || updating.value) return
|
|
updating.value = true
|
|
try {
|
|
await updateDeviceRuntime({
|
|
deviceId: deviceId.value,
|
|
...patch,
|
|
})
|
|
const data = await fetchDeviceRuntime({ deviceId: deviceId.value })
|
|
applyRuntime(data)
|
|
await refreshDeviceMeta()
|
|
} catch (err) {
|
|
uni.showToast({ title: getErrorMessage(err, '设置失败'), icon: 'none' })
|
|
} finally {
|
|
updating.value = false
|
|
}
|
|
}
|
|
|
|
function onSelectRunMode(mode: RunMode) {
|
|
if (runMode.value === mode) return
|
|
void patchRuntime({ runMode: mode })
|
|
}
|
|
|
|
function onSelectFanLevel(level: FanLevel) {
|
|
if (!isAutoRunMode(runMode.value)) return
|
|
if (fanLevel.value === level) return
|
|
void patchRuntime({ fanLevel: level })
|
|
}
|
|
|
|
function onSettings() {
|
|
uni.showToast({ title: '设备设置功能开发中', icon: 'none' })
|
|
}
|
|
|
|
function onFilterReplace() {
|
|
if (filterReplaced.value) return
|
|
filterReplaceDialogVisible.value = true
|
|
}
|
|
|
|
function onConfirmFilterReplace() {
|
|
filterReplaced.value = true
|
|
uni.showToast({ title: '操作成功', icon: 'success' })
|
|
}
|
|
|
|
const { startSyncLoop } = useDeviceBluetoothSync({
|
|
getDeviceId: () => deviceId.value,
|
|
getMac: () => deviceMac.value,
|
|
getRuntimePatch: () => ({
|
|
runMode: runMode.value,
|
|
fanLevel: fanLevel.value,
|
|
tvoc: tvoc.value ?? undefined,
|
|
powerMode: powerMode.value,
|
|
charging: charging.value ? '1' : '0',
|
|
}),
|
|
onBluetoothConnectedChange: (connected) => {
|
|
bluetoothConnected.value = connected
|
|
if (connected) {
|
|
isOnline.value = true
|
|
deviceStatus.value = '1'
|
|
}
|
|
},
|
|
onSyncTextChange: (text) => {
|
|
syncText.value = text
|
|
},
|
|
onSynced: async () => {
|
|
await refreshDeviceMeta()
|
|
const data = await fetchDeviceRuntime({ deviceId: deviceId.value })
|
|
applyRuntime(data)
|
|
},
|
|
})
|
|
|
|
onLoad((query?: DeviceDetailRouteQuery) => {
|
|
deviceId.value = Number(query?.deviceId) || 0
|
|
if (query?.name) deviceName.value = decodeURIComponent(String(query.name))
|
|
if (query?.locationName) {
|
|
locationName.value = decodeURIComponent(String(query.locationName))
|
|
}
|
|
if (query?.status) {
|
|
deviceStatus.value = String(query.status)
|
|
isOnline.value = query.status === '1'
|
|
}
|
|
if (query?.mac) deviceMac.value = decodeURIComponent(String(query.mac))
|
|
bluetoothConnected.value = isBluetoothConnected(query?.bluetoothConnected)
|
|
charging.value = query?.charging === '1'
|
|
void loadRuntime().then(() => {
|
|
startSyncLoop()
|
|
})
|
|
})
|
|
|
|
return {
|
|
deviceName,
|
|
connectionText,
|
|
isOnline,
|
|
tvocDisplay,
|
|
tvocLevel,
|
|
syncText,
|
|
runMode,
|
|
fanLevel,
|
|
powerModeText,
|
|
filterLife,
|
|
filterRemainText,
|
|
filterReplaced,
|
|
filterReplaceDialogVisible,
|
|
batteryDisplay,
|
|
batteryLevel,
|
|
charging,
|
|
loading,
|
|
showFanLevelControl,
|
|
runModeOptions: RUN_MODE_OPTIONS,
|
|
fanLevelOptions,
|
|
onSelectRunMode,
|
|
onSelectFanLevel,
|
|
onSettings,
|
|
onFilterReplace,
|
|
onConfirmFilterReplace,
|
|
}
|
|
}
|