Compare commits
7
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
78a495de60 | ||
|
|
ef13ff6a2b | ||
|
|
8b7a94b8c4 | ||
|
|
40b94dbad8 | ||
|
|
422a93dbe2 | ||
|
|
5c74edf001 | ||
|
|
937308e51d |
+25
@@ -25,6 +25,7 @@ try {
|
|||||||
|
|
||||||
const ADDONS_BASE_URL = BASE_URL.replace(/\/api\/shoot$/, "/api/shoot");
|
const ADDONS_BASE_URL = BASE_URL.replace(/\/api\/shoot$/, "/api/shoot");
|
||||||
|
|
||||||
|
// 统一处理业务接口请求,包含登录态、业务错误和 WiFi 连接空响应兼容。
|
||||||
function request(method, url, data = {}, baseUrl = BASE_URL) {
|
function request(method, url, data = {}, baseUrl = BASE_URL) {
|
||||||
const token = uni.getStorageSync(
|
const token = uni.getStorageSync(
|
||||||
`${uni.getAccountInfoSync().miniProgram.envVersion}_token`
|
`${uni.getAccountInfoSync().miniProgram.envVersion}_token`
|
||||||
@@ -39,6 +40,10 @@ function request(method, url, data = {}, baseUrl = BASE_URL) {
|
|||||||
data,
|
data,
|
||||||
timeout: 10000,
|
timeout: 10000,
|
||||||
success: (res) => {
|
success: (res) => {
|
||||||
|
if (url === "/user/hardwareBox/connectWifi" && res.statusCode === 200 && res.data && Object.keys(res.data).length === 0) {
|
||||||
|
resolve({});
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (res.data) {
|
if (res.data) {
|
||||||
const {code, data, message} = res.data;
|
const {code, data, message} = res.data;
|
||||||
if (code === 0) resolve(data);
|
if (code === 0) resolve(data);
|
||||||
@@ -473,6 +478,26 @@ export const getDeviceBatteryAPI = async () => {
|
|||||||
return request("GET", "/user/device/battery");
|
return request("GET", "/user/device/battery");
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 设备连接指定 WiFi,只下发 WiFi 凭证,不触发 OTA 升级。
|
||||||
|
export const connectDeviceWifiAPI = async (ssid, password) => {
|
||||||
|
return request("POST", "/user/hardwareBox/connectWifi", {ssid, password});
|
||||||
|
};
|
||||||
|
|
||||||
|
// 获取硬件盒子版本信息,用于判断当前设备是否需要 OTA 升级。
|
||||||
|
export const getHardwareBoxVersionAPI = async () => {
|
||||||
|
return request("GET", "/user/hardwareBox/version");
|
||||||
|
};
|
||||||
|
|
||||||
|
// 发送硬件盒子 OTA 更新指令,服务端会返回后续轮询使用的任务 ID。
|
||||||
|
export const sendHardwareBoxUpdateAPI = async (data) => {
|
||||||
|
return request("POST", "/user/hardwareBox/sendUpdate", data);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 根据任务 ID 获取硬件盒子 OTA 更新状态。
|
||||||
|
export const getHardwareBoxTaskStatusAPI = async (taskId) => {
|
||||||
|
return request("GET", `/user/hardwareBox/taskStatus?taskId=${taskId}`);
|
||||||
|
};
|
||||||
|
|
||||||
export const addNoteAPI = async (id, remark) => {
|
export const addNoteAPI = async (id, remark) => {
|
||||||
return request("POST", "/user/score/sheet/remark", {id, remark});
|
return request("POST", "/user/score/sheet/remark", {id, remark});
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,5 +1,10 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { computed } from "vue";
|
import { computed } from "vue";
|
||||||
|
import { getDeviceBatteryAPI } from "@/apis";
|
||||||
|
|
||||||
|
const OTA_MIN_BATTERY = 50;
|
||||||
|
const OTA_LOW_BATTERY_TEXT = "电量不足 50%,暂不支持 OTA 升级";
|
||||||
|
const OTA_OFFLINE_TEXT = "请先开启智能弓";
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
visible: {
|
visible: {
|
||||||
@@ -42,6 +47,32 @@ const isSuccess = computed(() => props.state === "update_success");
|
|||||||
const isFailure = computed(() => props.state === "update_failure");
|
const isFailure = computed(() => props.state === "update_failure");
|
||||||
// Clamp progress to keep the progress bar width within its container.
|
// Clamp progress to keep the progress bar width within its container.
|
||||||
const progressValue = computed(() => Math.min(100, Math.max(0, Number(props.progress) || 0)));
|
const progressValue = computed(() => Math.min(100, Math.max(0, Number(props.progress) || 0)));
|
||||||
|
|
||||||
|
// 点击立即更新前先校验设备在线状态,再校验设备电量。
|
||||||
|
const handleUpdateClick = async () => {
|
||||||
|
try {
|
||||||
|
const deviceStatus = await getDeviceBatteryAPI();
|
||||||
|
if (deviceStatus?.online !== true) {
|
||||||
|
uni.showToast({
|
||||||
|
title: OTA_OFFLINE_TEXT,
|
||||||
|
icon: "none",
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Number(deviceStatus?.battery) <= OTA_MIN_BATTERY) {
|
||||||
|
uni.showToast({
|
||||||
|
title: OTA_LOW_BATTERY_TEXT,
|
||||||
|
icon: "none",
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
emit("update");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
emit("update");
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@@ -91,7 +122,7 @@ const progressValue = computed(() => Math.min(100, Math.max(0, Number(props.prog
|
|||||||
<block v-if="isNewVersion">
|
<block v-if="isNewVersion">
|
||||||
<image src="../static/ota/new-ver.png" mode="aspectFit" class="new-ver-img" />
|
<image src="../static/ota/new-ver.png" mode="aspectFit" class="new-ver-img" />
|
||||||
<view v-if="version" class="version-tag-wrap">
|
<view v-if="version" class="version-tag-wrap">
|
||||||
<image src="../static/ota/ota-ver.png" mode="aspectFill" class="version-tag-bg-img" />
|
<image src="../static/ota/ota-ver.png" mode="aspectFit" class="version-tag-bg-img" />
|
||||||
<text class="version-tag">{{ version }}</text>
|
<text class="version-tag">{{ version }}</text>
|
||||||
</view>
|
</view>
|
||||||
<!-- 副标题:如“新版本将优化智能弓体验”,离下方详情 12rpx -->
|
<!-- 副标题:如“新版本将优化智能弓体验”,离下方详情 12rpx -->
|
||||||
@@ -99,7 +130,7 @@ const progressValue = computed(() => Math.min(100, Math.max(0, Number(props.prog
|
|||||||
<!-- 详细说明:如“升级前请确保:...” -->
|
<!-- 详细说明:如“升级前请确保:...” -->
|
||||||
<text v-if="changelog" class="changelog-text">{{ changelog }}</text>
|
<text v-if="changelog" class="changelog-text">{{ changelog }}</text>
|
||||||
<view class="btn-group">
|
<view class="btn-group">
|
||||||
<view class="primary-btn" @click="emit('update')">
|
<view class="primary-btn" @click="handleUpdateClick">
|
||||||
<text class="primary-btn-text">立即更新</text>
|
<text class="primary-btn-text">立即更新</text>
|
||||||
</view>
|
</view>
|
||||||
<text v-if="!forceUpdate" class="skip-text" @click="emit('skip')">暂不更新</text>
|
<text v-if="!forceUpdate" class="skip-text" @click="emit('skip')">暂不更新</text>
|
||||||
@@ -146,7 +177,7 @@ const progressValue = computed(() => Math.min(100, Math.max(0, Number(props.prog
|
|||||||
|
|
||||||
<!-- 关闭按钮(仅新版本状态,非强制更新时,位于弹窗下方) -->
|
<!-- 关闭按钮(仅新版本状态,非强制更新时,位于弹窗下方) -->
|
||||||
<view
|
<view
|
||||||
v-if="isNewVersion && !forceUpdate"
|
v-if="(isNewVersion || isFailure) && !forceUpdate"
|
||||||
class="ota-close-below"
|
class="ota-close-below"
|
||||||
@click="emit('close')"
|
@click="emit('close')"
|
||||||
>
|
>
|
||||||
@@ -270,6 +301,8 @@ const progressValue = computed(() => Math.min(100, Math.max(0, Number(props.prog
|
|||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
width: 116rpx;
|
||||||
|
height: 44rpx;
|
||||||
/* 离标题图 -10rpx,左边距 50rpx,离下方副标题 22rpx */
|
/* 离标题图 -10rpx,左边距 50rpx,离下方副标题 22rpx */
|
||||||
margin-top: -10rpx;
|
margin-top: -10rpx;
|
||||||
margin-left: 50rpx;
|
margin-left: 50rpx;
|
||||||
|
|||||||
+10
-1
@@ -198,7 +198,7 @@ const startHomeOtaUpdate = async () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// 点击立即更新时先判断设备是否已通过 WiFi 联网,已联网则首页直接更新,否则跳转 WiFi 页面。
|
// 点击立即更新时先判断设备是否在线并已通过 WiFi 联网,已联网则首页直接更新,否则跳转 WiFi 页面。
|
||||||
const handleOtaUpdate = async () => {
|
const handleOtaUpdate = async () => {
|
||||||
if (isStartingOta.value) return;
|
if (isStartingOta.value) return;
|
||||||
isStartingOta.value = true;
|
isStartingOta.value = true;
|
||||||
@@ -214,6 +214,15 @@ const handleOtaUpdate = async () => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (deviceStatus?.online !== true) {
|
||||||
|
isStartingOta.value = false;
|
||||||
|
uni.showToast({
|
||||||
|
title: "请先开启智能弓",
|
||||||
|
icon: "none",
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (String(deviceStatus?.netType || "").toLowerCase() === "wifi") {
|
if (String(deviceStatus?.netType || "").toLowerCase() === "wifi") {
|
||||||
startHomeOtaUpdate();
|
startHomeOtaUpdate();
|
||||||
return;
|
return;
|
||||||
|
|||||||
+35
-16
@@ -1,4 +1,4 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { ref, computed, onMounted, onUnmounted } from "vue";
|
import { ref, computed, onMounted, onUnmounted } from "vue";
|
||||||
import { onLoad, onShow } from "@dcloudio/uni-app";
|
import { onLoad, onShow } from "@dcloudio/uni-app";
|
||||||
import Container from "@/components/Container.vue";
|
import Container from "@/components/Container.vue";
|
||||||
@@ -52,8 +52,10 @@ let wifiConnectTimer = null;
|
|||||||
let wifiConnectRequestId = 0;
|
let wifiConnectRequestId = 0;
|
||||||
let wifiConnectPollCount = 0;
|
let wifiConnectPollCount = 0;
|
||||||
const WIFI_CONNECT_POLL_INTERVAL = 2000;
|
const WIFI_CONNECT_POLL_INTERVAL = 2000;
|
||||||
const WIFI_CONNECT_MAX_POLL_COUNT = 15;
|
const WIFI_CONNECT_MAX_POLL_COUNT = 30;
|
||||||
const WIFI_CONNECT_FAILED_TEXT = "连接失败,请检查WiFi密码或WiFi状态";
|
const WIFI_CONNECT_FAILED_TEXT = "连接失败,请检查WiFi密码或WiFi状态";
|
||||||
|
const OTA_MIN_BATTERY = 50;
|
||||||
|
const OTA_LOW_BATTERY_TEXT = "电量不足 50%,暂不支持 OTA 升级";
|
||||||
// 控制授权拒绝弹窗显示/隐藏
|
// 控制授权拒绝弹窗显示/隐藏
|
||||||
const wifiAuthDeniedVisible = ref(false);
|
const wifiAuthDeniedVisible = ref(false);
|
||||||
|
|
||||||
@@ -271,12 +273,20 @@ const cancelWifiConnectPolling = () => {
|
|||||||
uni.hideLoading();
|
uni.hideLoading();
|
||||||
};
|
};
|
||||||
|
|
||||||
// 判断设备是否已经在线且连接到 WiFi。
|
// 判断设备电量接口返回的 online/netType 字段,确定设备是否已通过 WiFi 在线。
|
||||||
|
// 返回值含义:true → WiFi 在线成功;"net_fail" → 设备走 4g 失败;false → 未就绪,需继续轮询。
|
||||||
const isDeviceConnectedByWifi = (deviceStatus) => {
|
const isDeviceConnectedByWifi = (deviceStatus) => {
|
||||||
return deviceStatus?.online === true && String(deviceStatus?.netType || "").toLowerCase() === "wifi";
|
// online 不为 true → 设备不在线,需继续轮询
|
||||||
|
if (deviceStatus?.online !== true) return false;
|
||||||
|
const netType = String(deviceStatus?.netType || "").toLowerCase();
|
||||||
|
// online:true + netType:4g → 设备已切 4g,WiFi 连接失败
|
||||||
|
if (netType === "4g") return "net_fail";
|
||||||
|
// online:true + netType:wifi → WiFi 连接成功
|
||||||
|
// online:true + netType:"" → 设备在线但 netType 暂未上报,继续轮询等待
|
||||||
|
return netType === "wifi";
|
||||||
};
|
};
|
||||||
|
|
||||||
// 轮询设备电量接口,确认设备已经切换到 WiFi 在线状态。
|
// 轮询设备电量接口,等待设备切到 WiFi 在线;netType:4g 快速失败,超时 30 次后放弃。
|
||||||
const waitForDeviceWifiConnected = (requestId) => {
|
const waitForDeviceWifiConnected = (requestId) => {
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
const poll = async () => {
|
const poll = async () => {
|
||||||
@@ -292,10 +302,19 @@ const waitForDeviceWifiConnected = (requestId) => {
|
|||||||
resolve(false);
|
resolve(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (isDeviceConnectedByWifi(deviceStatus)) {
|
const connResult = isDeviceConnectedByWifi(deviceStatus);
|
||||||
|
// online:true + netType:wifi → 成功
|
||||||
|
if (connResult === true) {
|
||||||
resolve(true);
|
resolve(true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
// online:true + netType:4g → 立即失败(设备已切 4g,WiFi 连不上)
|
||||||
|
if (connResult === "net_fail") {
|
||||||
|
resolve(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// online:false + netType:"" → 继续轮询
|
||||||
|
// online:true + netType:"" → 忽略,继续轮询(netType 暂未上报)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
if (requestId !== wifiConnectRequestId) {
|
if (requestId !== wifiConnectRequestId) {
|
||||||
resolve(false);
|
resolve(false);
|
||||||
@@ -436,8 +455,8 @@ const pollUpdateTaskStatus = (taskId) => {
|
|||||||
|
|
||||||
// 判断设备是否满足 OTA 更新条件,不满足时返回精确提示文案。
|
// 判断设备是否满足 OTA 更新条件,不满足时返回精确提示文案。
|
||||||
const getUpdateDisabledReason = (deviceStatus) => {
|
const getUpdateDisabledReason = (deviceStatus) => {
|
||||||
if (deviceStatus?.online !== true) return "设备已离线,请先开启设备并保持在线";
|
if (deviceStatus?.online !== true) return "请先开启智能弓";
|
||||||
if (Number(deviceStatus?.battery) <= 20) return "设备电量不足,请充电至 20% 以上后再更新";
|
if (Number(deviceStatus?.battery) <= OTA_MIN_BATTERY) return OTA_LOW_BATTERY_TEXT;
|
||||||
if (String(deviceStatus?.netType || "").toLowerCase() !== "wifi") return "设备当前未连接 WiFi,请先连接 WiFi 后再更新";
|
if (String(deviceStatus?.netType || "").toLowerCase() !== "wifi") return "设备当前未连接 WiFi,请先连接 WiFi 后再更新";
|
||||||
return "";
|
return "";
|
||||||
};
|
};
|
||||||
@@ -529,18 +548,18 @@ const handleWsFail = () => {
|
|||||||
failUpdate();
|
failUpdate();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 处理更新完成返回,兼容首页 OTA 弹窗入口和设备页普通入口。
|
||||||
const handleDone = () => {
|
const handleDone = () => {
|
||||||
uni.navigateBack({
|
|
||||||
delta: 1,
|
|
||||||
success() {
|
|
||||||
const pages = getCurrentPages();
|
const pages = getCurrentPages();
|
||||||
const prevPage = pages[pages.length - 2];
|
const prevPage = pages[pages.length - 2];
|
||||||
if (prevPage) {
|
const prevVm = prevPage?.$vm;
|
||||||
prevPage.$vm.otaState = "update_success";
|
|
||||||
prevPage.$vm.otaVisible = true;
|
if (prevVm && "otaState" in prevVm && "otaVisible" in prevVm) {
|
||||||
|
prevVm.otaState = "update_success";
|
||||||
|
prevVm.otaVisible = true;
|
||||||
}
|
}
|
||||||
},
|
|
||||||
});
|
uni.navigateBack({ delta: 1 });
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleRetry = () => {
|
const handleRetry = () => {
|
||||||
|
|||||||
Reference in New Issue
Block a user