mirror of
https://ghfast.top/https://github.com/aeroxw/easy_tdx_max.git
synced 2026-09-12 13:24:18 +08:00
feat(web): 品牌区显示应用版本号 — 新增 GET /api/v1/meta,前端启动拉取展示
This commit is contained in:
@@ -61,11 +61,32 @@ class SwitchResponse(BaseModel):
|
||||
message: str
|
||||
|
||||
|
||||
class MetaResponse(BaseModel):
|
||||
"""GET /meta 的响应。"""
|
||||
|
||||
version: str
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------- #
|
||||
# Routes
|
||||
# --------------------------------------------------------------------------- #
|
||||
|
||||
|
||||
@router.get("/meta", response_model=MetaResponse)
|
||||
async def get_meta() -> MetaResponse:
|
||||
"""应用元信息:版本号(WebUI 左上角展示)。
|
||||
|
||||
源码运行未装包元数据(importlib.metadata 不可用)时留空,前端不显示。
|
||||
"""
|
||||
try:
|
||||
from importlib.metadata import version
|
||||
|
||||
v: str = version("easy-tdx")
|
||||
except Exception: # noqa: BLE001 — 元数据缺失属正常场景,留空即可
|
||||
v = ""
|
||||
return MetaResponse(version=v)
|
||||
|
||||
|
||||
@router.get("/server/hosts", response_model=HostListResponse)
|
||||
async def list_hosts(request: Request) -> HostListResponse:
|
||||
"""列出所有候选 host + 当前正在使用的 host。
|
||||
|
||||
@@ -197,6 +197,28 @@ def test_realtime_router_endpoints():
|
||||
assert any("realtime" in p for p in paths)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Meta endpoint(WebUI 品牌区版本号展示)
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
def test_meta_endpoint_returns_version():
|
||||
"""GET /api/v1/meta 应返回 version 字段(已安装时为语义化版本)。"""
|
||||
pytest.importorskip("fastapi")
|
||||
from fastapi.testclient import TestClient
|
||||
|
||||
from easy_tdx.web import create_app
|
||||
|
||||
client = TestClient(create_app())
|
||||
resp = client.get("/api/v1/meta")
|
||||
assert resp.status_code == 200
|
||||
body = resp.json()
|
||||
assert set(body.keys()) == {"version"}
|
||||
assert isinstance(body["version"], str)
|
||||
# 本测试环境下包已安装(pip install -e .),应能取到版本号
|
||||
assert body["version"] != ""
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Task 10: CLI serve command
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
+19
-3
@@ -1,12 +1,19 @@
|
||||
<script setup lang="ts">
|
||||
// 根组件:侧边栏终端外壳 + 路由出口。
|
||||
// 布局借鉴专业看盘终端(侧边栏分组导航 + 底部实时连接状态徽标)。
|
||||
import { onMounted } from 'vue'
|
||||
import { onMounted, ref } from 'vue'
|
||||
|
||||
import { fetchMeta } from './api'
|
||||
import { useQuoteStore } from './stores/quotes'
|
||||
|
||||
const quoteStore = useQuoteStore()
|
||||
onMounted(() => quoteStore.connect())
|
||||
|
||||
// 应用版本号(GET /meta),品牌区展示;取不到(旧后端/源码未装包)则不显示
|
||||
const appVersion = ref('')
|
||||
onMounted(async () => {
|
||||
quoteStore.connect()
|
||||
appVersion.value = (await fetchMeta()).version
|
||||
})
|
||||
|
||||
const sseLabel: Record<string, string> = {
|
||||
connecting: '连接中',
|
||||
@@ -21,7 +28,10 @@ const sseLabel: Record<string, string> = {
|
||||
<aside class="sidebar">
|
||||
<div class="brand">
|
||||
<span class="brand-name">easy-tdx</span>
|
||||
<span class="brand-sub">行情终端</span>
|
||||
<span class="brand-sub">
|
||||
行情终端
|
||||
<span v-if="appVersion" class="brand-ver">v{{ appVersion }}</span>
|
||||
</span>
|
||||
</div>
|
||||
<nav class="side-nav">
|
||||
<div class="nav-group">行情</div>
|
||||
@@ -109,6 +119,12 @@ const sseLabel: Record<string, string> = {
|
||||
font-size: 11px;
|
||||
color: var(--text-dim);
|
||||
}
|
||||
.brand-ver {
|
||||
margin-left: 4px;
|
||||
font-size: 10px;
|
||||
opacity: 0.75;
|
||||
font-variant-numeric: tabular-nums;
|
||||
}
|
||||
.side-nav {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
import type {
|
||||
ApiError,
|
||||
AppMeta,
|
||||
BacktestRequest,
|
||||
BacktestResult,
|
||||
Bar,
|
||||
@@ -455,6 +456,17 @@ export async function switchServerHost(host: string): Promise<ServerSwitchResult
|
||||
return (await resp.json()) as ServerSwitchResult
|
||||
}
|
||||
|
||||
/** 应用元信息(版本号,品牌区展示)。失败返回空串,由调用方决定是否显示。 */
|
||||
export async function fetchMeta(): Promise<AppMeta> {
|
||||
try {
|
||||
const resp = await fetch(`${BASE}/meta`)
|
||||
if (!resp.ok) return { version: '' }
|
||||
return (await resp.json()) as AppMeta
|
||||
} catch {
|
||||
return { version: '' }
|
||||
}
|
||||
}
|
||||
|
||||
// ── 行情终端 ────────────────────────────────────────────────────────────────
|
||||
|
||||
/** 批量拉实时五档(REST 一次性;持续刷新走 SSE,见 stores/quotes.ts)。
|
||||
|
||||
@@ -455,6 +455,12 @@ export interface ServerSwitchResult {
|
||||
message: string
|
||||
}
|
||||
|
||||
/** GET /meta 的响应:应用元信息(版本号,WebUI 品牌区展示)。 */
|
||||
export interface AppMeta {
|
||||
/** 语义化版本(如 "1.32.5");源码运行元数据缺失时为空串 */
|
||||
version: string
|
||||
}
|
||||
|
||||
// ── 行情终端:实时五档(SSE / POST /api/v1/security/quotes) ─────────────────
|
||||
|
||||
/** 单只标的实时五档行情(后端 SecurityQuote 白名单投影,SSE 与 REST 同构)。 */
|
||||
|
||||
Reference in New Issue
Block a user