235 lines
7.7 KiB
JavaScript
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,
|
|
};
|
|
}
|