Files
iboard/src/api/mihome.js
T
jif2.zhang 95b9985e8b
Docker Build and Push / build-image (push) Successful in 5m46s
修复米家会话失效后不弹登录二维码
根因一: 过期检测形同虚设
- @zythum02/mijia-api 的 refreshToken() 在本地凭证字段齐全时直接返回成功,
  根本不发请求, 因此 checkAuth() 永远判定 ok, 过期后既不出横幅也不出扫码入口
- checkAuth() 改为真打一次 getHomesList() 验证 token; 成功缓存 5 分钟,
  失败只缓存 30 秒(便于网络恢复后自愈); 增加并发探测合并; 状态未变不写库
- getStatus() 以实时探测结果为准, DB 里的 status 仅在探测为 unknown 时兜底,
  避免残留的 ok 遮蔽已失效状态

根因二: 二维码图片 401 导致弹窗空白
- /api/mihome/reauthorize/qr-image 在 authRequired 之后, 而 <img src> 无法携带
  Authorization 头, 图片请求被拒, 用户看到的是空白/裂图
- 新增 fetchMihomeQrImage(): 带 JWT fetch 后转 blob URL 给 <img>, 并在卸载/换码时释放

其他修复
- EnvView 的 load 依赖 [status] 且成功回调又 setStatus, 造成 /status 无限重复请求;
  改为空依赖 + 函数式 setStatus; 首屏与重试走 ?force=1 强查
- 会话失效(非网络类错误)时自动弹出扫码窗, 每次挂载仅弹一次
- 扫码状态机新增 done 标记, 只有真正登录成功才算成功, 避免取消后误判
- 二维码 120s 超时自动续码(最多 2 次), 慢扫不再直接失败
- 取消后不再丢弃可能已成功的扫码结果
- scripts/mihome-login.mjs 适配 done 语义
- 同步更新设计文档 §5.2 / §5.4 / §6

注意: 前端需重新构建发布后生效。
2026-10-23 22:21:08 +08:00

50 lines
1.9 KiB
JavaScript

// 环境监控 API: 走后端 /api/mihome/* (凭证/token 不出前端)
import { api, getApiBase, getToken } from './client.js'
// 状态: 授权 + 家庭(设备) + 电量 + 最新样本 + 缺日 + 统计可用性
// force=true 让后端跳过 5 分钟认证缓存, 立刻回真实授权状态
export async function getMihomeStatus(force) {
return api('/mihome/status' + (force ? '?force=1' : ''))
}
// 历史: range = today | month | year
export async function getMihomeHistory(did, range) {
return api('/mihome/device/' + encodeURIComponent(did) + '/history?range=' + encodeURIComponent(range))
}
// 改别名 (alias 传空串 = 清空)
export async function setMihomeAlias(did, alias) {
return api('/mihome/device/' + encodeURIComponent(did), { method: 'PUT', body: { alias } })
}
// 立即同步
export async function syncMihome() {
return api('/mihome/sync', { method: 'POST' })
}
// 重授权
export async function startMihomeAuth() {
return api('/mihome/reauthorize', { method: 'POST' })
}
export async function getMihomeAuthStatus() {
return api('/mihome/reauthorize/status')
}
export async function cancelMihomeAuth() {
return api('/mihome/reauthorize/cancel', { method: 'POST' })
}
// 二维码图片: 后端接口在 authRequired 后面, 而 <img src> 无法带 Authorization 头,
// 直接塞地址会 401 (二维码位置一片空白). 这里用 fetch 带 JWT 取回二进制, 再转 blob URL 给 <img>.
export async function fetchMihomeQrImage() {
const token = getToken()
const res = await fetch(getApiBase() + '/api/mihome/reauthorize/qr-image', {
headers: token ? { Authorization: 'Bearer ' + token } : {},
cache: 'no-store',
})
if (!res.ok) {
const data = await res.json().catch(() => ({}))
throw new Error(data.error || '二维码加载失败 (' + res.status + ')')
}
const blob = await res.blob()
return URL.createObjectURL(blob)
}