Compare commits

...

4 Commits

Author SHA1 Message Date
508419180c 调整App头部显示,固定头部和分类
All checks were successful
Docker Build and Push / build-image (push) Successful in 4m56s
2026-08-08 19:40:39 +08:00
4f2becb99a 调整App头部显示,避免与系统消息栏重合
All checks were successful
Docker Build and Push / build-image (push) Successful in 4m51s
2026-08-08 19:20:30 +08:00
2fa7c7fc70 remove pagespy
All checks were successful
Docker Build and Push / build-image (push) Successful in 4m56s
2026-08-08 18:12:48 +08:00
1b330bdd4d 移除 reasonix.toml
All checks were successful
Docker Build and Push / build-image (push) Successful in 5m0s
2026-08-08 11:44:12 +08:00
12 changed files with 43 additions and 91 deletions

View File

@ -12,6 +12,11 @@ on:
jobs: jobs:
build-image: build-image:
runs-on: ubuntu-latest runs-on: ubuntu-latest
env:
# 关键: 显式固定 Android/OTA 后端地址, 覆盖 runner 环境里可能存在的
# 其他 VITE_API_BASE 值。否则 OTA 包里的前端可能连错后端, 导致
# "OTA 更新后登录失败/进不去内部"。与 android-build.yml 保持一致。
VITE_API_BASE: http://bh.vps.honor3.com:3001
steps: steps:
- uses: https://gitea.com/actions/checkout@v4 - uses: https://gitea.com/actions/checkout@v4

30
package-lock.json generated
View File

@ -8,7 +8,6 @@
"name": "iboard", "name": "iboard",
"version": "1.0.0", "version": "1.0.0",
"dependencies": { "dependencies": {
"@huolala-tech/page-spy": "^1.5.7",
"@prisma/adapter-mariadb": "^7.9.1", "@prisma/adapter-mariadb": "^7.9.1",
"@prisma/client": "^7.7.0", "@prisma/client": "^7.7.0",
"antd-mobile": "^5.42.3", "antd-mobile": "^5.42.3",
@ -807,20 +806,6 @@
"hono": "^4" "hono": "^4"
} }
}, },
"node_modules/@huolala-tech/page-spy": {
"version": "1.5.7",
"resolved": "https://registry.npmmirror.com/@huolala-tech/page-spy/-/page-spy-1.5.7.tgz",
"integrity": "sha512-M19WkH6K2taPpdi7gZ9Tz6v0vY/yW4ziffPXdU+p9+pdSmu1s0OhfxjcsWgERAYsaRLZNloSWqJZyWT5zsYIwA==",
"deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.",
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.13.0",
"copy-to-clipboard": "^3.3.1"
},
"engines": {
"node": ">=10"
}
},
"node_modules/@img/sharp-darwin-arm64": { "node_modules/@img/sharp-darwin-arm64": {
"version": "0.33.5", "version": "0.33.5",
"resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.33.5.tgz", "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.33.5.tgz",
@ -3242,15 +3227,6 @@
"integrity": "sha512-NXdYc3dLr47pBkpUCHtKSwIOQXLVn8dZEuywboCOJY/osA0wFSLlSawr3KN8qXJEyX66FcONTH8EIlVuK0yyFA==", "integrity": "sha512-NXdYc3dLr47pBkpUCHtKSwIOQXLVn8dZEuywboCOJY/osA0wFSLlSawr3KN8qXJEyX66FcONTH8EIlVuK0yyFA==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/copy-to-clipboard": {
"version": "3.3.3",
"resolved": "https://registry.npmmirror.com/copy-to-clipboard/-/copy-to-clipboard-3.3.3.tgz",
"integrity": "sha512-2KV8NhB5JqC3ky0r9PMCAZKbUHSwtEo4CwCs0KXgruG43gX5PMqDEBbVU4OUzw2MuAWUfsuFmWvEKG5QRfSnJA==",
"license": "MIT",
"dependencies": {
"toggle-selection": "^1.0.6"
}
},
"node_modules/cors": { "node_modules/cors": {
"version": "2.8.6", "version": "2.8.6",
"resolved": "https://registry.npmmirror.com/cors/-/cors-2.8.6.tgz", "resolved": "https://registry.npmmirror.com/cors/-/cors-2.8.6.tgz",
@ -6039,12 +6015,6 @@
"node": ">=18" "node": ">=18"
} }
}, },
"node_modules/toggle-selection": {
"version": "1.0.6",
"resolved": "https://registry.npmmirror.com/toggle-selection/-/toggle-selection-1.0.6.tgz",
"integrity": "sha512-BiZS+C1OS8g/q2RRbJmy59xpyghNBqrr6k5L/uKBGRsTfxmu3ffiRnd8mlGPUVayg8pvfi5urfnu8TU7DVOkLQ==",
"license": "MIT"
},
"node_modules/toidentifier": { "node_modules/toidentifier": {
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmmirror.com/toidentifier/-/toidentifier-1.0.1.tgz", "resolved": "https://registry.npmmirror.com/toidentifier/-/toidentifier-1.0.1.tgz",

View File

@ -27,7 +27,6 @@
"publish": "bash scripts/wsl/build-apk.sh release" "publish": "bash scripts/wsl/build-apk.sh release"
}, },
"dependencies": { "dependencies": {
"@huolala-tech/page-spy": "^1.5.7",
"@prisma/adapter-mariadb": "^7.9.1", "@prisma/adapter-mariadb": "^7.9.1",
"@prisma/client": "^7.7.0", "@prisma/client": "^7.7.0",
"antd-mobile": "^5.42.3", "antd-mobile": "^5.42.3",

View File

@ -1,2 +0,0 @@
[permissions]
allow = ["Bash=cd /d/workbench/iboard && node -e \"const y=require('js-yaml');try{y.load(require('fs').readFileSync('.gitea/workflows/android-build.yml','utf8'));console.log('YAML OK')}catch(e){console.error('YAML ERROR:',e.message);process.exit(1)}\""]

View File

@ -8,7 +8,7 @@
import { getApiBase, getToken } from './client.js' import { getApiBase, getToken } from './client.js'
import { APP_VERSION, BUILD_ID } from '../version.js' import { APP_VERSION, BUILD_ID } from '../version.js'
// 判断是否在 Tauri WebView 内 (与 src/debug/pagespy.js 同样的判定) // 判断是否在 Tauri WebView 内 (有 __TAURI_INTERNALS__ 即 Tauri 环境)
const inTauri = typeof window !== 'undefined' && '__TAURI_INTERNALS__' in window const inTauri = typeof window !== 'undefined' && '__TAURI_INTERNALS__' in window
// 拼接绝对 URL: 在 Tauri (VITE_API_BASE 有值) 时直连, 否则同源 // 拼接绝对 URL: 在 Tauri (VITE_API_BASE 有值) 时直连, 否则同源

View File

@ -1,21 +0,0 @@
// 仅在 Tauri WebView 内启用 PageSpy, 用于生产环境远程调试.
// web 模式 (Vite dev / 浏览器) 通过检测 window.__TAURI_INTERNALS__ 直接跳过,
// 配合 dynamic import 让 page-spy 这个 chunk 在 web 模式下完全不下载.
// VITE_PAGESPY_API 留空可关闭连接 (例如本地调试不想连远端 PageSpy 服务时).
// 加载失败不阻塞应用启动, 仅 console.warn 提示.
const PAGESPY_API = import.meta.env.VITE_PAGESPY_API || 'http://bh.vps.honor3.com:6752'
const inTauri = typeof window !== 'undefined' && '__TAURI_INTERNALS__' in window
if (inTauri && PAGESPY_API) {
// 动态 import: 仅在 Tauri 内才下载 page-spy chunk
import('@huolala-tech/page-spy')
.then(({ default: PageSpy }) => {
// PageSpy 默认会 hook fetch / XMLHttpRequest, 自动抓取网络请求和错误
const instance = new PageSpy({ api: PAGESPY_API })
window.__IBOARD_PAGESPY__ = instance
})
.catch((err) => {
console.warn('[PageSpy] init failed:', err)
})
}

View File

@ -1,28 +1,25 @@
// : Tauri WebView , web // UI : + (antd-mobile 5)
import './debug/pagespy.js' import 'antd-mobile/es/global'
// UI : + (antd-mobile 5) import React from 'react'
import 'antd-mobile/es/global' import ReactDOM from 'react-dom/client'
import { BrowserRouter } from 'react-router-dom'
import React from 'react' import App from './App.jsx'
import ReactDOM from 'react-dom/client' import { AuthProvider } from './auth/AuthContext.jsx'
import { BrowserRouter } from 'react-router-dom' import { initOta } from './api/ota.js'
import App from './App.jsx' import './styles/globals.css'
import { AuthProvider } from './auth/AuthContext.jsx'
import { initOta } from './api/ota.js' // OTA : Tauri
import './styles/globals.css' // - notifyReady: , (hotswap )
// - , React
// OTA : Tauri initOta()
// - notifyReady: , (hotswap )
// - , React ReactDOM.createRoot(document.getElementById('root')).render(
initOta() <React.StrictMode>
<BrowserRouter>
ReactDOM.createRoot(document.getElementById('root')).render( <AuthProvider>
<React.StrictMode> <App />
<BrowserRouter> </AuthProvider>
<AuthProvider> </BrowserRouter>
<App /> </React.StrictMode>,
</AuthProvider>
</BrowserRouter>
</React.StrictMode>,
) )

View File

@ -45,7 +45,7 @@ export default function HomePage() {
return ( return (
<div className="page-with-navbar"> <div className="page-with-navbar">
<NavBar back={null}>首页</NavBar> <NavBar back={null} />
<div className="home-content"> <div className="home-content">
<SwipeTabs tabs={tabs} active={active} onChange={setActive} /> <SwipeTabs tabs={tabs} active={active} onChange={setActive} />
</div> </div>

View File

@ -1,5 +1,6 @@
import { useState } from 'react' import { useState } from 'react'
import { useNavigate, useLocation, Routes, Route, Navigate } from 'react-router-dom' import { useNavigate, useLocation, Routes, Route, Navigate } from 'react-router-dom'
import { NavBar } from 'antd-mobile'
import SwipeTabs from '../components/SwipeTabs.jsx' import SwipeTabs from '../components/SwipeTabs.jsx'
import DataView from './macro/DataView.jsx' import DataView from './macro/DataView.jsx'
import StrategyView from './macro/StrategyView.jsx' import StrategyView from './macro/StrategyView.jsx'
@ -64,7 +65,8 @@ export default function MacroPage() {
} }
return ( return (
<div> <div className="page-with-navbar">
<NavBar back={null} />
<SwipeTabs tabs={tabs} active={active} onChange={onChange} /> <SwipeTabs tabs={tabs} active={active} onChange={onChange} />
</div> </div>
) )

View File

@ -111,7 +111,7 @@ export default function MePage() {
return ( return (
<div className="me-page"> <div className="me-page">
<NavBar back={null} className="me-navbar">我的</NavBar> <NavBar back={null} className="me-navbar" />
<div className="me-profile"> <div className="me-profile">
<Avatar <Avatar
className="me-avatar" className="me-avatar"

View File

@ -44,7 +44,7 @@ export default function MonitorPage() {
] ]
return ( return (
<div className="page-with-navbar"> <div className="page-with-navbar">
<NavBar back={null}>监控</NavBar> <NavBar back={null} />
<div className="monitor-content"> <div className="monitor-content">
<SwipeTabs tabs={tabs} active={active} onChange={setActive} /> <SwipeTabs tabs={tabs} active={active} onChange={setActive} />
</div> </div>

View File

@ -67,8 +67,10 @@ input, textarea, select { font: inherit; }
to { opacity: 1; transform: translateY(0); } to { opacity: 1; transform: translateY(0); }
} }
/* 带有 antd-mobile NavBar 的页面 (Home/Monitor/Me/Article) */ /* 带有 antd-mobile NavBar 的页面 (Home/Monitor/Macro/Article) */
.page-with-navbar { display: flex; flex-direction: column; min-height: 100%; } /* height:100% 让页面占满 app-main 高度, 内部 tab-content 独立滚动,
头部 NavBar 与分类 tab 固定在顶部不上滚 */
.page-with-navbar { display: flex; flex-direction: column; height: 100%; min-height: 0; }
.page-with-navbar .adm-error-block { flex: 1; } .page-with-navbar .adm-error-block { flex: 1; }
/* 底部 antd-mobile TabBar 定位 */ /* 底部 antd-mobile TabBar 定位 */
@ -92,7 +94,7 @@ input, textarea, select { font: inherit; }
.swipe-tabs-wrap { .swipe-tabs-wrap {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
height: 100%; flex: 1 1 auto;
min-height: 0; min-height: 0;
} }
.tab-content { .tab-content {
@ -209,7 +211,7 @@ input, textarea, select { font: inherit; }
.me-logout { color: var(--color-danger); } .me-logout { color: var(--color-danger); }
.me-version { text-align: center; font-size: 12px; color: var(--color-muted); padding: 18px 0 8px; } .me-version { text-align: center; font-size: 12px; color: var(--color-muted); padding: 18px 0 8px; }
/* 首页模块: 报警 + 新闻 */ /* 首页模块: 报警 + 新闻 */
.home-content { padding: 0 0 16px; } .home-content { padding: 0 0 16px; flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; }
.home-content .adm-tabs-content { --content-padding: 0; } .home-content .adm-tabs-content { --content-padding: 0; }
.home-content .tab-label { display: inline-flex; align-items: center; gap: 4px; } .home-content .tab-label { display: inline-flex; align-items: center; gap: 4px; }
.home-section { padding: 0 12px 16px; } .home-section { padding: 0 12px 16px; }
@ -238,7 +240,7 @@ input, textarea, select { font: inherit; }
.news-content { font-size: 15px; line-height: 1.75; color: #333; white-space: pre-wrap; word-break: break-word; } .news-content { font-size: 15px; line-height: 1.75; color: #333; white-space: pre-wrap; word-break: break-word; }
.news-content-empty { margin-top: 12px; font-size: 12px; color: var(--color-muted); } .news-content-empty { margin-top: 12px; font-size: 12px; color: var(--color-muted); }
/* ================== 监控页 ================== */ /* ================== 监控页 ================== */
.monitor-content { padding: 0 0 16px; } .monitor-content { padding: 0 0 16px; flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; }
.monitor-content .adm-tabs-content { --content-padding: 0; } .monitor-content .adm-tabs-content { --content-padding: 0; }
.monitor-tip { font-size: 11px; color: var(--color-muted); padding: 8px 14px 2px; } .monitor-tip { font-size: 11px; color: var(--color-muted); padding: 8px 14px 2px; }
.monitor-loading { padding: 40px 0; text-align: center; color: var(--color-muted); font-size: 13px; } .monitor-loading { padding: 40px 0; text-align: center; color: var(--color-muted); font-size: 13px; }