修改 ota cicd
Docker Build and Push / build-image (push) Successful in 6m37s

This commit is contained in:
cheney
2026-08-07 17:10:07 +08:00
parent 22a36fb213
commit add3ff8831
9 changed files with 141 additions and 15 deletions
+33
View File
@@ -0,0 +1,33 @@
import { useEffect, useRef } from 'react'
// 页面从后台恢复到前台时调用 refetch (Tauri 移动端/桌面通用, 不引库)
// - visibilitychange: Tauri 移动端 (iOS WKWebView / Android WebView) 唯一可靠的前后台机制,
// 回前台时 document.visibilityState 必然变为 'visible'
// - window focus: 桌面端 (WebView2) 兜底, 部分场景不派发 DOM focus 但原生窗口焦点事件可靠
// 用法: const load = useCallback(...); useRefreshOnVisible(load)
// 回调通过 ref 持有, effect 只绑定一次, 不随每次渲染重新订阅
export default function useRefreshOnVisible(refetch) {
const fnRef = useRef(refetch)
fnRef.current = refetch
useEffect(() => {
// 回前台时 visibilitychange 与 focus 会接连触发, 用 300ms 窗口节流避免重复请求
let lastTs = 0
const fire = () => {
const now = Date.now()
if (now - lastTs < 300) return
lastTs = now
fnRef.current?.()
}
const onVisibility = () => {
if (document.visibilityState === 'visible') fire()
}
const onFocus = () => fire()
document.addEventListener('visibilitychange', onVisibility)
window.addEventListener('focus', onFocus)
return () => {
document.removeEventListener('visibilitychange', onVisibility)
window.removeEventListener('focus', onFocus)
}
}, [])
}
+40
View File
@@ -3,6 +3,7 @@ import { useNavigate } from 'react-router-dom'
import { NavBar, Card, Empty, DotLoading, Badge } from 'antd-mobile'
import { api } from '../api/client.js'
import SwipeTabs from '../components/SwipeTabs.jsx'
import useRefreshOnVisible from '../hooks/useRefreshOnVisible.js'
// 首页: 报警模块 + 新闻模块
// - 报警: World Bank 与妙想 MCP 跨源同 (指标, 周期) 数据差异超阈值 (按时间倒序)
@@ -82,6 +83,26 @@ function AlertSection({ onCount }) {
}, [done, onCount])
useEffect(() => { fetchPage() }, [])
// 后台回前台: 重置游标重拉第一页, 新数据到了再更新视图
const reload = useCallback(async () => {
if (inFlightRef.current) return
inFlightRef.current = true
setLoading(true)
try {
const data = await api('/alerts?limit=10')
setItems(data.items || [])
onCount?.(data.total ?? (data.items?.length || 0))
cursorRef.current = data.nextCursor
setDone(!data.nextCursor)
} catch (e) {
console.error('alerts reload error', e)
setDone(true)
} finally {
inFlightRef.current = false
setLoading(false)
}
}, [onCount])
useRefreshOnVisible(reload)
useEffect(() => {
if (done || items.length === 0) return
const el = sentinelRef.current
@@ -152,6 +173,25 @@ function NewsSection() {
}, [done])
useEffect(() => { fetchPage() }, [])
// 后台回前台: 重置游标重拉第一页, 新数据到了再更新视图
const reload = useCallback(async () => {
if (inFlightRef.current) return
inFlightRef.current = true
setLoading(true)
try {
const data = await api('/news?limit=10')
setItems(data.items || [])
cursorRef.current = data.nextCursor
setDone(!data.nextCursor)
} catch (e) {
console.error('news reload error', e)
setDone(true)
} finally {
inFlightRef.current = false
setLoading(false)
}
}, [])
useRefreshOnVisible(reload)
useEffect(() => {
if (done || items.length === 0) return
const el = sentinelRef.current
+4
View File
@@ -3,6 +3,7 @@ import { useNavigate } from 'react-router-dom'
import { NavBar, Card, Empty, DotLoading } from 'antd-mobile'
import { api } from '../api/client.js'
import SwipeTabs from '../components/SwipeTabs.jsx'
import useRefreshOnVisible from '../hooks/useRefreshOnVisible.js'
// 监控页: 两个横向分类
// - 主机监控: 实时数据来自 komari (服务端实时代理, 不落库), 点击节点看 24h 时序
@@ -74,6 +75,9 @@ function ServerView() {
return () => clearInterval(timer)
}, [load])
// 后台回前台时立即静默刷新 (不闪 loading), 优于等下一轮 30s 轮询
useRefreshOnVisible(() => load(true))
return (
<div className="server-list">
{items === null && <div className="monitor-loading"><DotLoading /> 加载中...</div>}
+10 -10
View File
@@ -1,9 +1,10 @@
import { useEffect, useState } from 'react'
import { useEffect, useState, useCallback } from 'react'
import { useParams, useNavigate } from 'react-router-dom'
import { LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip, Legend, ResponsiveContainer } from 'recharts'
import { Card, List, NavBar } from 'antd-mobile'
import { api } from '../../api/client.js'
import TrendBadge, { calcTrend, lastPoint } from '../../components/TrendBadge.jsx'
import useRefreshOnVisible from '../../hooks/useRefreshOnVisible.js'
// 经济数据
// 列表态 (默认): 列出所有指标, 每行显示最新值 + 趋势徽标, 点击进入详情
@@ -24,19 +25,18 @@ export default function DataView() {
const { name } = useParams()
const navigate = useNavigate()
useEffect(() => {
let cancelled = false
const load = useCallback(() => {
setLoading(true)
api('/indicators')
.then((data) => {
if (cancelled) return
setIndicators(data.indicators || [])
})
.catch((e) => !cancelled && setErr(e.message))
.finally(() => !cancelled && setLoading(false))
return () => { cancelled = true }
.then((data) => { setErr(''); setIndicators(data.indicators || []) })
.catch((e) => setErr(e.message))
.finally(() => setLoading(false))
}, [])
useEffect(() => { load() }, [load])
// 后台回前台时重新拉取
useRefreshOnVisible(load)
if (loading) return <div className="loading">加载中...</div>
if (err) return <div className="error-banner">{err}</div>
if (!indicators.length) return <div className="empty">暂无指标数据, 请先执行 npm run db:seed</div>