869 lines
28 KiB
JavaScript
869 lines
28 KiB
JavaScript
window.onload = function () {
|
||
function getStatus() {
|
||
return new Promise((resolve, reject) => {
|
||
fetch("/get_status")
|
||
.then((response) => {
|
||
if (!response.ok) {
|
||
reject(new Error("Network response was not ok"));
|
||
}
|
||
return response.json();
|
||
})
|
||
.then((data) => resolve(data)) // 如果成功,返回数据
|
||
.catch((error) => {
|
||
console.error("There was a problem with the fetch operation:", error);
|
||
reject(error); // 如果发生错误,返回错误
|
||
});
|
||
});
|
||
}
|
||
|
||
// 虚拟模式
|
||
const developBtn = document.getElementById("develop-btn");
|
||
const modeRealText = document.getElementById("mode-real-text");
|
||
const changePower = document.getElementById("change-power");
|
||
const changePowerText = document.getElementById("change-power-text");
|
||
|
||
const loadBtn = document.getElementById("load-btn");
|
||
const loadText = document.getElementById("load-text");
|
||
// 虚拟模式显示
|
||
modeRealText.innerText =
|
||
parseInt(localStorage.getItem("modeReal")) === 0 ? "开" : "关";
|
||
// 力控方式按钮显示
|
||
changePower.style.display =
|
||
parseInt(localStorage.getItem("modeReal")) === 0 ? "flex" : "none";
|
||
loadText.innerText =
|
||
parseInt(localStorage.getItem("loadMode")) === 1 ? "开" : "关";
|
||
|
||
developBtn.addEventListener("click", function () {
|
||
getStatus()
|
||
.then(async (data) => {
|
||
if (data.is_massaging || data.is_pause) {
|
||
let stopPleaseText = await getPopupText("stopPleaseText");
|
||
showPopup(stopPleaseText, { confirm: true, cancel: false });
|
||
return;
|
||
} else {
|
||
if (parseInt(localStorage.getItem("loadMode")) === 1) {
|
||
let noToggleText = await getPopupText("noToggleText");
|
||
showPopup(noToggleText);
|
||
return;
|
||
} else {
|
||
const modeReal =
|
||
parseInt(localStorage.getItem("modeReal")) === 0 ? 0 : 1;
|
||
if (modeReal === 1) {
|
||
localStorage.setItem("modeReal", 0);
|
||
modeRealText.innerText = "开";
|
||
changePower.style.display = "flex";
|
||
changePowerText.innerText = localStorage.getItem("powerControl")
|
||
? localStorage.getItem("powerControl")
|
||
: "导纳";
|
||
} else {
|
||
localStorage.setItem("modeReal", 1);
|
||
modeRealText.innerText = "关";
|
||
changePower.style.display = "none";
|
||
}
|
||
}
|
||
}
|
||
})
|
||
.catch((error) => {
|
||
console.error("Error:", error);
|
||
showPopup(error, { confirm: true, cancel: false });
|
||
});
|
||
});
|
||
|
||
loadBtn.addEventListener("click", function () {
|
||
getStatus()
|
||
.then((data) => {
|
||
if (data.is_massaging || data.is_pause) {
|
||
showPopup("请先停止按摩...", { confirm: true, cancel: false });
|
||
return;
|
||
} else {
|
||
if (parseInt(localStorage.getItem("modeReal")) === 0) {
|
||
showPopup("循环模式下和虚拟模式无法同时开启", { confirm: true, cancel: false });
|
||
return;
|
||
} else {
|
||
const loadMode =
|
||
parseInt(localStorage.getItem("loadMode")) === 1 ? 1 : 0;
|
||
if (loadMode === 0) {
|
||
localStorage.setItem("loadMode", 1);
|
||
loadText.innerText = "开";
|
||
} else {
|
||
localStorage.setItem("loadMode", 0);
|
||
loadText.innerText = "关";
|
||
}
|
||
}
|
||
}
|
||
})
|
||
.catch((error) => {
|
||
console.error("Error:", error);
|
||
showPopup(error, { confirm: true, cancel: false });
|
||
});
|
||
});
|
||
|
||
const changePowerBtn = document.getElementById("change-power-btn");
|
||
changePowerText.innerText = localStorage.getItem("powerControl")
|
||
? localStorage.getItem("powerControl")
|
||
: "导纳";
|
||
changePowerBtn.addEventListener("click", function () {
|
||
let powerControl = localStorage.getItem("powerControl");
|
||
if (powerControl === "导纳" || !powerControl) {
|
||
localStorage.setItem("powerControl", "力位混合");
|
||
changePowerText.innerText = "力位混合";
|
||
} else {
|
||
localStorage.setItem("powerControl", "导纳");
|
||
changePowerText.innerText = "导纳";
|
||
}
|
||
});
|
||
|
||
// 机械臂打包按钮
|
||
const robotPackBtn = document.getElementById("robot-pack-btn");
|
||
robotPackBtn.addEventListener("click", function () {
|
||
getStatus()
|
||
.then((data) => {
|
||
if (data.is_massaging || data.is_pause) {
|
||
showPopup("请先停止按摩...", { confirm: true, cancel: false });
|
||
return;
|
||
} else {
|
||
|
||
showPopup("准备运动到打包位置,请确定是否已经取下按摩头!").then(
|
||
(confirm) => {
|
||
if (confirm) {
|
||
fetch("/pack_mode", {
|
||
method: "POST",
|
||
headers: {
|
||
"Content-Type": "application/x-www-form-urlencoded", // 表单数据类型
|
||
},
|
||
});
|
||
|
||
|
||
localStorage.setItem("modeReal", 1);
|
||
modeRealText.innerText = "关";
|
||
changePower.style.display = "none";
|
||
|
||
localStorage.setItem("loadMode", 0);
|
||
loadText.innerText = "关";
|
||
}
|
||
}
|
||
);
|
||
|
||
}
|
||
})
|
||
.catch((error) => {
|
||
console.error("Error:", error);
|
||
showPopup(error, { confirm: true, cancel: false });
|
||
});
|
||
});
|
||
|
||
let jumpModeInterval = null;
|
||
|
||
|
||
const massageLog = document.getElementById("massage-log-btn");
|
||
const uiLog = document.getElementById("ui-log-btn");
|
||
const langLog = document.getElementById("language-log-btn");
|
||
|
||
massageLog.addEventListener("click", function () {
|
||
loadLogData("show", "massage");
|
||
// showLogModal();
|
||
})
|
||
uiLog.addEventListener("click", function () {
|
||
loadLogData("show", "ui");
|
||
// showLogModal();
|
||
})
|
||
langLog.addEventListener("click", function () {
|
||
loadLogData("show", "language");
|
||
// showLogModal();
|
||
})
|
||
|
||
const logModal = document.getElementById("log-modal");
|
||
const logBg = document.getElementById("log-bg");
|
||
const logInput = document.getElementById("log-input");
|
||
const logSearch = document.getElementById("log-search");
|
||
const logRefresh = document.getElementById("log-refresh");
|
||
const logText = document.getElementById("log-text");
|
||
|
||
logBg.addEventListener("click", function () {
|
||
logModal.style.display = "none";
|
||
logInput.value = "";
|
||
logText.innerHTML = "";
|
||
});
|
||
|
||
// 自定义日志高亮规则
|
||
Prism.languages.log = {
|
||
'info': /INFO/,
|
||
'error': /ERROR/,
|
||
'warning': /WARNING/,
|
||
'timestamp': /\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}/
|
||
};
|
||
|
||
let currentPage = 1; // 当前页码
|
||
let totalPages = 1; // 总页数
|
||
let currentLogType = ""; // 当前日志类型
|
||
let currentKeyword = ""; // 当前搜索关键字
|
||
let isLoading = false; // 是否正在加载数据
|
||
|
||
// 加载日志数据
|
||
function loadLogData(clickType, type, keyword = "", page = 1) {
|
||
if (isLoading) return; // 如果正在加载,则退出
|
||
isLoading = true;
|
||
|
||
currentLogType = type;
|
||
currentKeyword = keyword;
|
||
currentPage = page;
|
||
|
||
// 显示加载指示器
|
||
document.getElementById("loading-indicator").style.display = "block";
|
||
|
||
getLog(type, keyword, page)
|
||
.then((data) => {
|
||
if (clickType === 'show') {
|
||
showLogModal();
|
||
}
|
||
|
||
// 如果是第一页,清空内容
|
||
if (page === 1) {
|
||
logText.innerHTML = `<pre><code class="language-log">${data.data.join("\n")}</code></pre>`;
|
||
} else {
|
||
// 追加新内容
|
||
const existingContent = logText.querySelector("code").textContent;
|
||
logText.innerHTML = `<pre><code class="language-log">${existingContent}\n${data.data.join("\n")}</code></pre>`;
|
||
}
|
||
|
||
// 调用 Prism.js 高亮
|
||
Prism.highlightAll();
|
||
|
||
// 更新总页数
|
||
totalPages = Math.ceil(data.total / data.pageSize);
|
||
|
||
// 隐藏加载指示器
|
||
document.getElementById("loading-indicator").style.display = "none";
|
||
isLoading = false;
|
||
})
|
||
.catch((error) => {
|
||
console.error("加载日志失败:", error);
|
||
document.getElementById("loading-indicator").style.display = "none";
|
||
isLoading = false;
|
||
});
|
||
}
|
||
|
||
logText.addEventListener("scroll", () => {
|
||
if (
|
||
logText.scrollTop + logText.clientHeight >=
|
||
logText.scrollHeight - 10 // 接近底部时触发
|
||
) {
|
||
if (currentPage < totalPages) {
|
||
loadLogData('scroll', currentLogType, currentKeyword, currentPage + 1);
|
||
}
|
||
}
|
||
});
|
||
|
||
logSearch.addEventListener("click", () => {
|
||
const keyword = logInput.value.trim();
|
||
loadLogData('search', currentLogType, keyword, 1); // 搜索时重置到第一页
|
||
});
|
||
|
||
logRefresh.addEventListener("click", () => {
|
||
logInput.value = currentKeyword;
|
||
loadLogData('refresh', currentLogType, currentKeyword, currentPage);
|
||
});
|
||
|
||
logInput.addEventListener("keyup", (event) => {
|
||
if (event.keyCode === 13) {
|
||
const keyword = logInput.value.trim();
|
||
loadLogData('search', currentLogType, keyword, 1); // 按下回车时搜索
|
||
}
|
||
});
|
||
|
||
// 显示日志弹窗
|
||
function showLogModal() {
|
||
logModal.style.display = "block";
|
||
}
|
||
|
||
function getLog(type, keyword = "", page = 1, pageSize = 400) {
|
||
return new Promise((resolve, reject) => {
|
||
fetch(`/get_log?type=${type}&keyword=${keyword}&page=${page}&pageSize=${pageSize}`)
|
||
.then((response) => response.json())
|
||
.then((data) => {
|
||
if (data.error) {
|
||
showPopup(data.error, { confirm: true, cancel: false });
|
||
reject(data.error); // 如果有错误,拒绝 Promise
|
||
} else {
|
||
resolve(data); // 如果成功,返回数据
|
||
}
|
||
})
|
||
.catch((error) => {
|
||
console.error(error);
|
||
showPopup(error, { confirm: true, cancel: false });
|
||
reject(error); // 捕获错误并拒绝 Promise
|
||
});
|
||
});
|
||
}
|
||
|
||
// 获取按摩头配置
|
||
function loadMassageHeads() {
|
||
fetch('/get_massage_heads')
|
||
.then(response => response.json())
|
||
.then(data => {
|
||
if (data.status === 'success') {
|
||
updateHeadCheckboxes(data.data);
|
||
} else {
|
||
showPopup('获取按摩头配置失败: ' + data.message, {confirm: true, cancel: false});
|
||
}
|
||
})
|
||
.catch(error => {
|
||
showPopup('请求出错: ' + error, {confirm: true, cancel: false});
|
||
});
|
||
}
|
||
|
||
const saveBtn = document.getElementById('save-heads-btn');
|
||
|
||
document.querySelectorAll('input[name="head-option"]').forEach(checkbox => {
|
||
checkbox.addEventListener('change', updateSaveButtonState);
|
||
});
|
||
|
||
// 更新保存按钮状态
|
||
function updateSaveButtonState() {
|
||
const hasSelected = Array.from(document.querySelectorAll('input[name="head-option"]:checked')).length > 0;
|
||
|
||
if (!hasSelected) {
|
||
saveBtn.disabled = true;
|
||
saveBtn.style.opacity = '0.4';
|
||
showPopup('请至少选择一个按摩头', { confirm: true, cancel: false })
|
||
} else {
|
||
saveBtn.disabled = false;
|
||
saveBtn.style.opacity = '1';
|
||
}
|
||
}
|
||
|
||
// 保存按摩头配置
|
||
function saveMassageHeads() {
|
||
if(saveBtn.style.opacity == '0.4') {
|
||
return;
|
||
}
|
||
getStatus()
|
||
.then((data) => {
|
||
if (data.is_massaging || data.is_pause) {
|
||
showPopup("按摩中无法设置", { confirm: true, cancel: false });
|
||
return;
|
||
} else {
|
||
const headsConfig = {};
|
||
document.querySelectorAll('input[name="head-option"]').forEach(checkbox => {
|
||
const headId = checkbox.value;
|
||
headsConfig[headId] = {
|
||
display: checkbox.checked,
|
||
name: document.querySelector(`label[for="head-${headId}"]`).textContent
|
||
};
|
||
});
|
||
|
||
fetch('/set_massage_heads', {
|
||
method: 'POST',
|
||
headers: {
|
||
'Content-Type': 'application/json',
|
||
},
|
||
body: JSON.stringify({ heads_config: headsConfig })
|
||
})
|
||
.then(response => response.json())
|
||
.then(data => {
|
||
if (data.status === 'success') {
|
||
showPopup('按摩头设置已保存', {confirm: true, cancel: false});
|
||
} else {
|
||
showPopup('保存失败: ' + data.message, {confirm: true, cancel: false});
|
||
}
|
||
})
|
||
.catch(error => {
|
||
showPopup('保存出错: ' + error, {confirm: true, cancel: false});
|
||
});
|
||
}
|
||
})
|
||
.catch((error) => {
|
||
console.error("Error:", error);
|
||
showPopup(error, { confirm: true, cancel: false });
|
||
});
|
||
}
|
||
|
||
async function getJumpMode() {
|
||
try {
|
||
const response = await fetch('/get_jump_mode');
|
||
const { data } = await response.json();
|
||
document.getElementById('jump-text').textContent =
|
||
data.enabled ? '已开启' : '已关闭';
|
||
jumpModeInterval = data.enabled;
|
||
} catch (error) {
|
||
console.error('获取跳跃模式失败:', error);
|
||
showPopup('获取跳跃模式失败');
|
||
}
|
||
}
|
||
|
||
// 切换跳跃模式
|
||
document.getElementById('jump-toggle-btn').addEventListener('click', async () => {
|
||
getStatus()
|
||
.then(async (data) => {
|
||
if (data.is_massaging || data.is_pause) {
|
||
showPopup("请先停止按摩...", { confirm: true, cancel: false });
|
||
return;
|
||
} else {
|
||
if(jumpModeInterval === null || jumpModeInterval === undefined) {
|
||
try {
|
||
const current = await fetch('/get_jump_mode').then(res => res.json());
|
||
const newState = !current.data.enabled;
|
||
toggleJumpMode(newState);
|
||
} catch (error) {
|
||
console.error('切换跳跃模式失败:', error);
|
||
showPopup('切换跳跃模式失败');
|
||
}
|
||
} else {
|
||
const newState = !jumpModeInterval;
|
||
toggleJumpMode(newState);
|
||
}
|
||
}
|
||
})
|
||
.catch((error) => {
|
||
console.error("Error:", error);
|
||
showPopup(error, { confirm: true, cancel: false });
|
||
});
|
||
});
|
||
|
||
async function toggleJumpMode(newState) {
|
||
// 设置新状态
|
||
const response = await fetch('/set_jump_mode', {
|
||
method: 'POST',
|
||
headers: {
|
||
'Content-Type': 'application/json',
|
||
},
|
||
body: JSON.stringify({ enabled: newState })
|
||
});
|
||
|
||
const result = await response.json();
|
||
if (result.status === 'success') {
|
||
document.getElementById('jump-text').textContent = newState ? '已开启' : '已关闭';
|
||
jumpModeInterval = newState;
|
||
showPopup(`跳跃模式已${newState ? '开启' : '关闭'}`);
|
||
} else {
|
||
showPopup('操作失败: ' + result.message);
|
||
}
|
||
}
|
||
|
||
// 更新复选框状态
|
||
function updateHeadCheckboxes(headsConfig) {
|
||
for (const [headId, config] of Object.entries(headsConfig)) {
|
||
const checkbox = document.getElementById(`head-${headId}`);
|
||
if (checkbox) {
|
||
checkbox.checked = config.display;
|
||
}
|
||
}
|
||
}
|
||
|
||
// 绑定保存按钮事件
|
||
saveBtn.addEventListener('click', saveMassageHeads);
|
||
|
||
loadMassageHeads();
|
||
|
||
getJumpMode();
|
||
};
|
||
|
||
const wifiModal = document.getElementById("wifi-modal");
|
||
|
||
function getWifiStatus() {
|
||
fetch("/is_connected")
|
||
.then((response) => response.json())
|
||
.then((data) => {
|
||
const myWifi = document.getElementById("my-wifi");
|
||
if (data.is_connected) {
|
||
myWifi.style.display = "flex";
|
||
getWifiInfo();
|
||
} else {
|
||
myWifi.style.display = "none";
|
||
showPopup("星耀按摩机器人未连接网络,请检查网络连接后重试。", {confirm: true, cancel: false});
|
||
}
|
||
});
|
||
}
|
||
const wifiName = document.getElementById("wifi-name");
|
||
|
||
function getWifiInfo() {
|
||
fetch("/get_current_connection")
|
||
.then((response) => response.json())
|
||
.then((data) => {
|
||
const wifiTxt = document.getElementById("wifi-txt");
|
||
if (data.connection_info[0].name) {
|
||
wifiTxt.innerText = data.connection_info[0].name;
|
||
wifiName.innerText = data.connection_info[0].name;
|
||
} else {
|
||
wifiTxt.innerText = "未知网络或未连接";
|
||
wifiTxt.style.color = "rgba(145, 66, 197, 1)";
|
||
}
|
||
});
|
||
}
|
||
|
||
let isAllowClick = true;
|
||
|
||
let selectedSsid = ""; // 全局变量,用于存储当前选择的 SSID
|
||
let selectedWifiImg = ""; // 全局变量,用于存储当前选择的 Wi-Fi 信号强度图片
|
||
let selectedWifiImgElement = null;
|
||
|
||
function scanWifi() {
|
||
const wifiList = document.getElementById("wifi-list");
|
||
wifiList.innerHTML = `<div class="loading-box">
|
||
<img
|
||
class="loading-img"
|
||
src="/static/images/setting/loading.gif"
|
||
alt=""
|
||
/>
|
||
</div>`;
|
||
fetch("/scan_wifi")
|
||
.then((response) => response.json())
|
||
.then((data) => {
|
||
// 先清空列表
|
||
wifiList.innerHTML = "";
|
||
if (data.wifi_networks.length === 0) {
|
||
wifiList.innerHTML = `扫描不到wifi`;
|
||
} else {
|
||
// 再添加扫描到的wifi
|
||
data.wifi_networks.forEach((network) => {
|
||
if (network.SSID !== wifiName.innerText) {
|
||
let wifiImg =
|
||
network.Signal <= 33
|
||
? "/static/images/setting/wifi-small.png"
|
||
: network.Signal <= 66
|
||
? "/static/images/setting/wifi-medium.png"
|
||
: "/static/images/setting/wifi.png";
|
||
wifiList.innerHTML += `<div class="wifi-item" data-ssid="${network.SSID}">
|
||
<div class="wifi-is-connected">
|
||
<div class="wifi-type">
|
||
<img
|
||
src="${wifiImg}"
|
||
alt=""
|
||
class="wifi-signal-img"
|
||
/>
|
||
</div>
|
||
</div>
|
||
<div class="wifi-name">${network.SSID}</div>
|
||
<div class="right-content">
|
||
<div class="is-locked">
|
||
<img
|
||
src="/static/images/setting/lock.png"
|
||
alt=""
|
||
/>
|
||
</div>
|
||
</div>
|
||
</div>`;
|
||
}
|
||
});
|
||
|
||
// 为每个 wifi-item 添加点击事件监听器
|
||
const wifiItems = document.querySelectorAll(".wifi-item");
|
||
wifiItems.forEach((item) => {
|
||
item.addEventListener("click", function () {
|
||
if (isAllowClick === true) {
|
||
selectedSsid = this.getAttribute("data-ssid"); // 存储当前选中的 SSID
|
||
console.log("点击了 Wi-Fi 网络:", selectedSsid);
|
||
|
||
// 获取当前点击项中的图片元素,并保存它
|
||
selectedWifiImgElement = this.querySelector(".wifi-signal-img");
|
||
selectedWifiImg = selectedWifiImgElement.src;
|
||
|
||
// 显示密码框
|
||
showPwdModal().then((confirm) => {
|
||
if (confirm) {
|
||
wifiPwdCheck();
|
||
}
|
||
});
|
||
} else {
|
||
return;
|
||
}
|
||
});
|
||
});
|
||
}
|
||
});
|
||
}
|
||
|
||
const pwdModal = document.getElementById("pwd-modal");
|
||
const pwdInput = document.getElementById("pwd-input");
|
||
|
||
let pwdResolve;
|
||
|
||
function showPwdModal() {
|
||
pwdModal.style.display = "flex";
|
||
pwdInput.value = "";
|
||
pwdInput.focus();
|
||
|
||
// 返回Promise,等待用户选择
|
||
return new Promise((resolve) => {
|
||
pwdResolve = resolve; // 保存 resolve 函数
|
||
});
|
||
}
|
||
|
||
// 绑定 keydown 事件
|
||
pwdInput.addEventListener('keydown', function (event) {
|
||
// 检查按下的键是否是 Enter 键
|
||
if (event.key === 'Enter' || event.keyCode === 13) {
|
||
// 回车键按下时的逻辑
|
||
pwdConfirm()
|
||
}
|
||
});
|
||
|
||
function pwdConfirm() {
|
||
pwdModal.style.display = "none";
|
||
pwdResolve(true);
|
||
}
|
||
|
||
function pwdCancel() {
|
||
pwdModal.style.display = "none";
|
||
pwdResolve(false);
|
||
}
|
||
|
||
function wifiPwdCheck() {
|
||
selectedWifiImgElement.src = "/static/images/setting/loading.gif"; // 更换为加载中图片
|
||
isAllowClick = false;
|
||
if (pwdInput.value === "") {
|
||
showPopup("密码不能为空。", {confirm: true, cancel: false});
|
||
isAllowClick = true;
|
||
// 恢复之前选择的 Wi-Fi 图标
|
||
if (selectedWifiImgElement) {
|
||
selectedWifiImgElement.src = selectedWifiImg; // 恢复为原始图标
|
||
}
|
||
return;
|
||
} else if (pwdInput.value.length < 8) {
|
||
showPopup("密码长度必须大于等于8位。", {confirm: true, cancel: false});
|
||
isAllowClick = true;
|
||
// 恢复之前选择的 Wi-Fi 图标
|
||
if (selectedWifiImgElement) {
|
||
selectedWifiImgElement.src = selectedWifiImg; // 恢复为原始图标
|
||
}
|
||
return;
|
||
} else {
|
||
let timeout = false; // 是否超时的标志
|
||
|
||
// 设置 20 秒超时计时器
|
||
const timer = setTimeout(() => {
|
||
timeout = true; // 标记超时
|
||
showPopup(
|
||
`连接成功,请将平板的WI-FI连接到与按摩机器人同一网络:${selectedSsid},再手动重启APP。`,
|
||
{ confirm: false, cancel: false }
|
||
);
|
||
}, 20000); // 20秒后触发超时逻辑
|
||
|
||
fetch("/connect_wifi", {
|
||
method: "POST",
|
||
headers: {
|
||
"Content-Type": "application/json",
|
||
},
|
||
body: JSON.stringify({
|
||
ssid: selectedSsid,
|
||
password: pwdInput.value,
|
||
}),
|
||
})
|
||
.then((response) => response.json())
|
||
.then((data) => {
|
||
let num = 20;
|
||
|
||
let interval = setInterval(() => {
|
||
if (timeout) {
|
||
clearInterval(interval); // 如果超时,则停止轮询
|
||
return;
|
||
}
|
||
|
||
if (data.message.status === "error") {
|
||
showPopup(data.message.message, { confirm: true });
|
||
isAllowClick = true;
|
||
// 恢复之前选择的 Wi-Fi 图标
|
||
if (selectedWifiImgElement) {
|
||
selectedWifiImgElement.src = selectedWifiImg; // 恢复为原始图标
|
||
}
|
||
clearInterval(interval); // 错误时停止轮询
|
||
clearTimeout(timer); // 停止超时计时器
|
||
}
|
||
|
||
if (num === 0) {
|
||
clearInterval(interval); // 如果 20 秒后还没有返回错误,则显示成功信息
|
||
showPopup(
|
||
`连接成功,请将平板的WI-FI连接到与按摩机器人同一网络:${selectedSsid},再手动重启APP。`,
|
||
{ confirm: false, cancel: false }
|
||
);
|
||
clearTimeout(timer); // 结束超时计时器
|
||
}
|
||
num--;
|
||
}, 1000); // 每秒检查一次
|
||
})
|
||
.catch(() => {
|
||
isAllowClick = true;
|
||
clearTimeout(timer); // 如果请求出错,取消超时计时器
|
||
});
|
||
}
|
||
}
|
||
|
||
getWifiStatus();
|
||
scanWifi();
|
||
|
||
document.getElementById("scan-btn").addEventListener("click", function () {
|
||
wifiModal.style.display = "flex";
|
||
scanWifi();
|
||
});
|
||
document.getElementById("rescan-btn").addEventListener("click", function () {
|
||
scanWifi();
|
||
});
|
||
document
|
||
.getElementById("modal-level")
|
||
.addEventListener("click", function (e) {
|
||
if (isAllowClick === true) {
|
||
wifiModal.style.display = "none";
|
||
} else {
|
||
return;
|
||
}
|
||
});
|
||
|
||
const showBoardBtn = document.getElementById("show-board-btn");
|
||
const boardImg = document.getElementById("board-img");
|
||
const calibrationControls = document.getElementById("calibration-controls");
|
||
const startCalibrationBtn = document.getElementById("start-calibration-btn");
|
||
const calibrationResultModal = document.getElementById("calibration-result-modal");
|
||
const rotationMatrixResult = document.getElementById("rotation-matrix-result");
|
||
const translationVectorResult = document.getElementById("translation-vector-result");
|
||
const intrinsicsResult = document.getElementById("intrinsics-result");
|
||
|
||
// 存储最新的标定结果
|
||
let currentCalibrationResults = null;
|
||
|
||
// 使用已存在的socket连接
|
||
if (typeof socket === 'undefined') {
|
||
console.warn('Socket.IO connection not found, creating new one');
|
||
window.socket = io();
|
||
}
|
||
|
||
|
||
|
||
// 格式化矩阵显示
|
||
function formatMatrix(matrix) {
|
||
// 处理内参字典格式
|
||
if (typeof matrix === 'object' && matrix !== null && !Array.isArray(matrix) && 'fx' in matrix) {
|
||
let result = '';
|
||
// 添加主要参数
|
||
result += `fx: ${matrix.fx.toFixed(6)}\n`;
|
||
result += `fy: ${matrix.fy.toFixed(6)}\n`;
|
||
result += `cx: ${matrix.cx.toFixed(6)}\n`;
|
||
result += `cy: ${matrix.cy.toFixed(6)}\n`;
|
||
|
||
// 添加畸变系数
|
||
if (matrix.distortion_coeffs) {
|
||
result += `畸变系数:\n`;
|
||
const distCoeffs = matrix.distortion_coeffs;
|
||
result += ` k1: ${distCoeffs.k1.toFixed(6)}\n`;
|
||
result += ` k2: ${distCoeffs.k2.toFixed(6)}\n`;
|
||
result += ` p1: ${distCoeffs.p1.toFixed(6)}\n`;
|
||
result += ` p2: ${distCoeffs.p2.toFixed(6)}\n`;
|
||
result += ` k3: ${distCoeffs.k3.toFixed(6)}`;
|
||
}
|
||
return result;
|
||
} else if (!Array.isArray(matrix)) {
|
||
return JSON.stringify(matrix);
|
||
}
|
||
|
||
return matrix.map(row =>
|
||
Array.isArray(row)
|
||
? row.map(v => v.toFixed(6)).join(' ')
|
||
: row.toFixed(6) // 直接对非数组的 row 使用 toFixed(6)
|
||
).join('\n');
|
||
}
|
||
|
||
|
||
// 监听标定状态更新
|
||
socket.on('calibration_status', function (data) {
|
||
console.log('Received calibration status:', data);
|
||
switch (data.status) {
|
||
case 'running':
|
||
startCalibrationBtn.disabled = true;
|
||
startCalibrationBtn.textContent = '标定中...';
|
||
break;
|
||
case 'collecting':
|
||
startCalibrationBtn.textContent = '收集数据...';
|
||
break;
|
||
case 'calibrating':
|
||
startCalibrationBtn.textContent = '计算参数...';
|
||
break;
|
||
case 'completed':
|
||
startCalibrationBtn.disabled = false;
|
||
startCalibrationBtn.textContent = '开始标定';
|
||
// 保存当前标定结果
|
||
currentCalibrationResults = data.results;
|
||
// 格式化并显示标定结果
|
||
console.log(data.results.rotation_matrix)
|
||
console.log(data.results.translation_vector)
|
||
console.log(data.results.intrinsics)
|
||
rotationMatrixResult.textContent = formatMatrix(data.results.rotation_matrix);
|
||
translationVectorResult.textContent = formatMatrix(data.results.translation_vector);
|
||
intrinsicsResult.textContent = formatMatrix(data.results.intrinsics);
|
||
calibrationResultModal.style.display = "block";
|
||
break;
|
||
case 'error':
|
||
startCalibrationBtn.disabled = false;
|
||
startCalibrationBtn.textContent = '开始标定';
|
||
showPopup('标定失败:' + data.message);
|
||
break;
|
||
}
|
||
});
|
||
|
||
showBoardBtn.addEventListener("click", function () {
|
||
console.log('Showing board image');
|
||
boardImg.style.display = "block";
|
||
calibrationControls.style.display = "block";
|
||
});
|
||
|
||
boardImg.addEventListener("dblclick", function () {
|
||
console.log('Hiding board image');
|
||
boardImg.style.display = "none";
|
||
calibrationControls.style.display = "none";
|
||
calibrationResultModal.style.display = "none";
|
||
});
|
||
|
||
startCalibrationBtn.addEventListener("click", function () {
|
||
console.log('Starting calibration');
|
||
fetch('/start_calibration', {
|
||
method: 'POST'
|
||
})
|
||
.then(response => response.json())
|
||
.then(data => {
|
||
if (data.status === 'error') {
|
||
showPopup(data.message);
|
||
}
|
||
})
|
||
.catch(error => {
|
||
console.error('Error:', error);
|
||
showPopup('启动标定失败:' + error.message);
|
||
});
|
||
});
|
||
|
||
function saveCalibrationResult() {
|
||
if (!currentCalibrationResults) {
|
||
showPopup('没有可保存的标定结果');
|
||
return;
|
||
}
|
||
|
||
fetch('/save_calibration', {
|
||
method: 'POST',
|
||
headers: {
|
||
'Content-Type': 'application/json'
|
||
},
|
||
body: JSON.stringify({
|
||
rotation_matrix: currentCalibrationResults.rotation_matrix,
|
||
translation_vector: currentCalibrationResults.translation_vector,
|
||
intrinsics: currentCalibrationResults.intrinsics
|
||
})
|
||
})
|
||
.then(response => response.json())
|
||
.then(data => {
|
||
if (data.status === 'success') {
|
||
showPopup('标定结果保存成功');
|
||
calibrationResultModal.style.display = "none";
|
||
boardImg.style.display = "none";
|
||
calibrationControls.style.display = "none";
|
||
} else {
|
||
showPopup('保存失败:' + data.message);
|
||
}
|
||
})
|
||
.catch(error => {
|
||
console.error('Error:', error);
|
||
showPopup('保存失败:' + error.message);
|
||
});
|
||
}
|
||
|
||
function cancelCalibrationResult() {
|
||
calibrationResultModal.style.display = "none";
|
||
currentCalibrationResults = null;
|
||
}
|