auto_trade_sys/frontend/src/App.jsx
薇薇安 45a654f654 a
2026-01-21 21:45:10 +08:00

129 lines
4.3 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import React, { useEffect, useState } from 'react'
import { BrowserRouter as Router, Routes, Route, Link } from 'react-router-dom'
import ConfigPanel from './components/ConfigPanel'
import ConfigGuide from './components/ConfigGuide'
import TradeList from './components/TradeList'
import StatsDashboard from './components/StatsDashboard'
import Recommendations from './components/Recommendations'
import LogMonitor from './components/LogMonitor'
import AccountSelector from './components/AccountSelector'
import Login from './components/Login'
import { api, clearAuthToken, clearCurrentAccountId, setCurrentAccountId, getCurrentAccountId } from './services/api'
import './App.css'
function App() {
const [me, setMe] = useState(null)
const [checking, setChecking] = useState(true)
const refreshMe = async () => {
try {
const u = await api.me()
setMe(u)
// 登录后默认选择账号(避免 admin/用户切换时沿用旧 accountId
try {
const list = await api.getAccounts()
const accounts = Array.isArray(list) ? list : []
const active = accounts.filter((a) => String(a?.status || 'active') === 'active')
const isAdmin = (u?.role || '') === 'admin'
let target = null
if (isAdmin) {
// 管理员:默认选第一个 active 账号(避免沿用旧值导致“看起来还是上个账号”)
target = active[0]?.id || accounts[0]?.id
} else {
// 普通用户:优先选“自己的账号”(且必须 active否则选第一个 active
const uid = parseInt(String(u?.id || ''), 10)
const match = active.find((a) => parseInt(String(a?.id || ''), 10) === uid)
target = match?.id || active[0]?.id || accounts[0]?.id
}
if (target) {
const cur = getCurrentAccountId()
const next = parseInt(String(target), 10)
if (Number.isFinite(next) && next > 0 && cur !== next) setCurrentAccountId(next)
}
} catch (e) {
// ignore
}
} catch (e) {
setMe(null)
} finally {
setChecking(false)
}
}
useEffect(() => {
refreshMe()
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [])
const isAdmin = (me?.role || '') === 'admin'
if (checking) {
return (
<div className="app">
<div className="main-content" style={{ padding: '24px' }}>
正在初始化...
</div>
</div>
)
}
if (!me) {
return <Login onLoggedIn={refreshMe} />
}
return (
<Router>
<div className="app">
<nav className="navbar">
<div className="nav-container">
<div className="nav-left">
<h1 className="nav-title">自动交易系统</h1>
<AccountSelector />
</div>
<div className="nav-links">
<Link to="/">仪表板</Link>
<Link to="/recommendations">交易推荐</Link>
<Link to="/config">配置</Link>
<Link to="/trades">交易记录</Link>
{isAdmin ? <Link to="/logs">日志监控</Link> : null}
</div>
<div className="nav-user">
<span className="nav-user-name">
{me?.username ? me.username : 'user'}{isAdmin ? '(管理员)' : ''}
</span>
<button
type="button"
className="nav-logout"
onClick={() => {
clearAuthToken()
clearCurrentAccountId()
setMe(null)
setChecking(false)
}}
>
退出
</button>
</div>
</div>
</nav>
<main className="main-content">
<Routes>
<Route path="/" element={<StatsDashboard />} />
<Route path="/recommendations" element={<Recommendations />} />
<Route path="/config" element={<ConfigPanel currentUser={me} />} />
<Route path="/config/guide" element={<ConfigGuide />} />
<Route path="/trades" element={<TradeList />} />
<Route path="/logs" element={isAdmin ? <LogMonitor /> : <div style={{ padding: '24px' }}>无权限</div>} />
</Routes>
</main>
</div>
</Router>
)
}
export default App