feat:绑定设备和设备详情
This commit is contained in:
223
src/pages/device/detail/use-device-detail.ts
Normal file
223
src/pages/device/detail/use-device-detail.ts
Normal file
@@ -0,0 +1,223 @@
|
||||
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,
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user