Files
shoot-miniprograms/src/pages/device/composables/useDeviceStatus.js
T
2026-09-24 17:10:10 +08:00

235 lines
7.7 KiB
JavaScript

import { computed, ref } from "vue";
import {
getDeviceDetailAPI,
getMyDevicesAPI,
unbindDeviceAPI,
} from "@/apis";
export const DEVICE_NAME_STORAGE_KEY = "device_name_overrides";
export function useDeviceStatus({
user,
device,
deviceStatus,
deviceUsageDuration,
online,
updateDevice,
updateDeviceUsageDuration,
clearDevice,
unbindDialogVisible,
}) {
const deviceDetails = ref({});
let deviceDetailRequestVersion = 0;
const isDeviceOnline = computed(
() => deviceStatus.value.online === true || online.value === true
);
const isDeviceCharging = computed(
() => isDeviceOnline.value && deviceStatus.value.charging === true
);
const statusText = computed(() => {
if (!isDeviceOnline.value) return "未连接";
return isDeviceCharging.value ? "已连接(充电中)" : "已连接";
});
const statusClass = computed(() =>
isDeviceOnline.value ? "device-status--online" : "device-status--offline"
);
const battery = computed(() => {
const rawValue = deviceStatus.value.battery ?? deviceStatus.value.power;
if (rawValue === null || rawValue === undefined || rawValue === "") return null;
const value = Number(rawValue);
return Number.isFinite(value) ? Math.min(100, Math.max(0, value)) : null;
});
const batteryText = computed(() =>
battery.value === null ? "暂无数据" : `${battery.value}%`
);
const normalizeDuration = (value) => {
if (value == null || String(value).trim() === "") return null;
const seconds = Number(value);
return Number.isFinite(seconds) && seconds >= 0 ? seconds : null;
};
const onlineDurationText = computed(() => {
const currentDeviceId = String(device.value.deviceId || "");
const cachedDuration =
String(deviceUsageDuration.value.deviceId || "") === currentDeviceId
? normalizeDuration(deviceUsageDuration.value.seconds)
: null;
const durations = [
normalizeDuration(deviceStatus.value.onlineDuration),
normalizeDuration(deviceDetails.value.onlineDuration),
cachedDuration,
].filter((value) => value !== null);
if (!durations.length) return "--";
const seconds = Math.max(...durations);
// 累计时长应单调递增,页面按完整分钟展示当前已知最大值。
const totalMinutes = Math.floor(seconds / 60);
const hours = Math.floor(totalMinutes / 60);
const minutes = totalMinutes % 60;
return hours > 0 ? `${hours}小时${minutes}分钟` : `${minutes}分钟`;
});
const networkType = computed(() =>
String(deviceStatus.value.netType ?? "").trim().toLowerCase()
);
const networkText = computed(() => {
const netType = networkType.value;
if (netType === "wifi") return "WiFi";
if (netType === "4g") return "4G";
return isDeviceOnline.value ? "在线" : "未连接";
});
const maskedDeviceId = computed(() => {
const id = String(device.value.deviceId || "");
if (!id) return "暂无设备编号";
return "*****";
});
const deviceRows = computed(() => [
{ label: "设备型号", value: deviceDetails.value.model || "射灵智能弓" },
{ label: "当前电量", value: batteryText.value },
{ label: "连接方式", value: networkText.value },
{ label: "设备编号", value: maskedDeviceId.value },
]);
const getDeviceNameOverrides = () => {
const value = uni.getStorageSync(DEVICE_NAME_STORAGE_KEY);
return value && typeof value === "object" ? value : {};
};
const refreshDeviceDetails = async () => {
const deviceId = device.value.deviceId;
if (!deviceId) return null;
const requestVersion = ++deviceDetailRequestVersion;
try {
const detailResponse = await getDeviceDetailAPI(deviceId);
const detail = detailResponse?.detail || detailResponse?.data?.detail;
if (
!detail ||
typeof detail !== "object" ||
requestVersion !== deviceDetailRequestVersion ||
device.value.deviceId !== deviceId
) {
return null;
}
deviceDetails.value = {
...deviceDetails.value,
...detail,
deviceModelName: detail.deviceModelName ?? "",
latestVersion: detail.latestVersion ?? "",
needUpdate: detail.needUpdate ?? false,
forceUpdate: detail.forceUpdate ?? false,
version: detail.version ?? "",
bindTime: String(
detail.bindTime ?? deviceDetails.value.bindTime ?? ""
).trim(),
qrCodeUrl: String(
detail.qrCodeUrl ?? deviceDetails.value.qrCodeUrl ?? ""
).trim(),
};
updateDeviceUsageDuration(detail.onlineDuration, deviceId);
return detail;
} catch (error) {
// 实时刷新失败时保留当前页面数据,等待下次通知或页面重新显示。
console.log("刷新设备详情失败", error);
return null;
}
};
const syncDeviceBinding = async () => {
if (!user.value.id) return;
try {
const devices = await getMyDevicesAPI();
if (Array.isArray(devices?.bindings) && devices.bindings.length > 0) {
const currentDevice = devices.bindings[0];
const nameOverrides = getDeviceNameOverrides();
// 二维码和绑定时间仅取详情接口,绑定列表不能作为这两项的回退数据。
let latestDevice = {
...currentDevice,
deviceModelName: "",
latestVersion: "",
needUpdate: false,
forceUpdate: false,
version: "",
bindTime: "",
qrCodeUrl: "",
};
try {
const detailResponse = await getDeviceDetailAPI(currentDevice.deviceId);
const detail = detailResponse?.detail || detailResponse?.data?.detail;
if (detail && typeof detail === "object") {
latestDevice = {
...currentDevice,
...detail,
deviceModelName: detail.deviceModelName ?? "",
bindTime: String(detail.bindTime ?? "").trim(),
qrCodeUrl: String(detail.qrCodeUrl ?? "").trim(),
deviceName:
detail.deviceAlias || detail.deviceName || currentDevice.deviceName,
};
}
} catch (error) {
// 详情接口失败时保留绑定关系,二维码和绑定时间仍保持为空。
console.log("获取设备详情失败", error);
}
deviceDetails.value = latestDevice;
updateDevice(
latestDevice.deviceId,
nameOverrides[latestDevice.deviceId] ||
latestDevice.deviceAlias ||
latestDevice.deviceName ||
latestDevice.name ||
"我的智能弓"
);
updateDeviceUsageDuration(latestDevice.onlineDuration, latestDevice.deviceId);
return;
}
clearDevice();
deviceDetailRequestVersion += 1;
deviceDetails.value = {};
} catch (error) {
console.log("同步设备绑定失败", error);
}
};
const unbindDevice = async () => {
if (!device.value.deviceId) return;
try {
await unbindDeviceAPI(device.value.deviceId);
uni.setStorageSync("calibration", false);
clearDevice();
deviceDetailRequestVersion += 1;
deviceDetails.value = {};
unbindDialogVisible.value = false;
uni.showToast({ title: "解绑成功", icon: "success" });
} catch (error) {
console.error("解绑设备失败", error);
if (error?.type === "DEVICE_BIND_INVALID") {
clearDevice();
unbindDialogVisible.value = false;
}
}
};
return {
batteryText,
deviceDetails,
deviceRows,
getDeviceNameOverrides,
isDeviceCharging,
isDeviceOnline,
maskedDeviceId,
networkText,
networkType,
onlineDurationText,
refreshDeviceDetails,
statusClass,
statusText,
syncDeviceBinding,
unbindDevice,
};
}