This commit is contained in:
aaron 2026-04-16 20:13:45 +08:00
parent 02b4f79137
commit d7f7ad305c
12 changed files with 110 additions and 46 deletions

View File

@ -1,5 +1,9 @@
FROM python:3.13-slim
# 设置东八区时区
ENV TZ=Asia/Shanghai
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
WORKDIR /app
COPY requirements.txt .
@ -12,4 +16,4 @@ RUN mkdir -p /app/data
EXPOSE 8000
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]

Binary file not shown.

View File

@ -6,8 +6,10 @@ services:
- ./backend/.env
environment:
- ASTOCK_DATABASE_URL=sqlite:///./data/astock.db
- TZ=Asia/Shanghai
volumes:
- db_data:/app/data
- /etc/localtime:/etc/localtime:ro
expose:
- "8000"
# 生产环境不需要映射端口,前端容器通过 Docker 网络内部访问
@ -24,6 +26,9 @@ services:
- backend
environment:
- BACKEND_URL=http://backend:8000
- TZ=Asia/Shanghai
volumes:
- /etc/localtime:/etc/localtime:ro
volumes:
db_data:
db_data:

View File

@ -1,9 +1,9 @@
{
"pages": {
"/recommendations/page": [
"/page": [
"static/chunks/webpack.js",
"static/chunks/main-app.js",
"static/chunks/app/recommendations/page.js"
"static/chunks/app/page.js"
],
"/layout": [
"static/chunks/webpack.js",
@ -11,15 +11,15 @@
"static/css/app/layout.css",
"static/chunks/app/layout.js"
],
"/page": [
"/recommendations/page": [
"static/chunks/webpack.js",
"static/chunks/main-app.js",
"static/chunks/app/page.js"
"static/chunks/app/recommendations/page.js"
],
"/users/page": [
"/sectors/page": [
"static/chunks/webpack.js",
"static/chunks/main-app.js",
"static/chunks/app/users/page.js"
"static/chunks/app/sectors/page.js"
]
}
}

File diff suppressed because one or more lines are too long

View File

@ -1 +1,8 @@
{}
{
"app/sectors/page.tsx -> echarts": {
"id": "app/sectors/page.tsx -> echarts",
"files": [
"static/chunks/_app-pages-browser_node_modules_echarts_index_js.js"
]
}
}

View File

@ -1,5 +1,5 @@
{
"/users/page": "app/users/page.js",
"/page": "app/page.js",
"/recommendations/page": "app/recommendations/page.js",
"/page": "app/page.js"
"/sectors/page": "app/sectors/page.js"
}

View File

@ -1 +1 @@
self.__REACT_LOADABLE_MANIFEST="{}"
self.__REACT_LOADABLE_MANIFEST="{\"app/sectors/page.tsx -> echarts\":{\"id\":\"app/sectors/page.tsx -> echarts\",\"files\":[\"static/chunks/_app-pages-browser_node_modules_echarts_index_js.js\"]}}"

View File

@ -1,5 +1,5 @@
{
"node": {},
"edge": {},
"encryptionKey": "vMdxWQqJbs8lx1fn0MelZryKaOD9juru8raACaKF7MY="
"encryptionKey": "ep/FQ9LpllRmRWJwm9g4skQlubaCcrDQ9a9sMtJTxBw="
}

View File

@ -125,7 +125,7 @@
/******/
/******/ /* webpack/runtime/getFullHash */
/******/ (() => {
/******/ __webpack_require__.h = () => ("51f130523eab8ec6")
/******/ __webpack_require__.h = () => ("08a4c58ab1067fd1")
/******/ })();
/******/
/******/ /* webpack/runtime/hasOwnProperty shorthand */

File diff suppressed because one or more lines are too long

View File

@ -60,10 +60,23 @@ export default function DashboardPage() {
}, [loadData]);
useWebSocket(
useCallback(() => {
loadData();
useCallback((msg: { type: string; count?: number; scan_mode?: string; message?: string }) => {
if (msg.type === "scan_update") {
const modeLabel = msg.scan_mode === "intraday" ? "盘中实时" : "盘后";
setRefreshResult(`${modeLabel}扫描完成,发现 ${msg.count ?? 0} 只股票`);
setRefreshing(false);
loadData();
setTimeout(() => setRefreshResult(null), 5000);
} else if (msg.type === "scan_error") {
setRefreshResult("扫描失败,请重试");
setRefreshing(false);
setTimeout(() => setRefreshResult(null), 5000);
} else {
// 其他消息类型(如 llm_analysis_ready刷新数据
loadData();
}
}, [loadData]),
["llm_analysis_ready", "sector_scan_ready", "scan_complete"]
["scan_update", "scan_error", "llm_analysis_ready", "sector_scan_ready", "scan_complete"]
);
const handleRefresh = async () => {
@ -72,18 +85,20 @@ export default function DashboardPage() {
try {
const res = await postAPI<{
status: string;
count: number;
temperature: number;
scan_mode: string;
message?: string;
is_trading: boolean;
}>("/api/recommendations/refresh?scan_session=manual");
const modeLabel = res.scan_mode === "intraday" ? "盘中实时" : "盘后";
setRefreshResult(`${modeLabel}扫描完成,发现 ${res.count} 只股票`);
await loadData();
if (res.status === "already_running") {
setRefreshResult(res.message || "扫描正在执行中,请稍候");
// 保持 refreshing等待 WS 推送完成
} else if (res.status === "scanning") {
setRefreshResult("扫描已启动,完成后自动刷新...");
// 保持 refreshing等待 WS 推送
}
} catch (e) {
console.error("刷新失败:", e);
setRefreshResult("扫描失败,请重试");
} finally {
console.error("触发扫描失败:", e);
setRefreshResult("触发扫描失败,请重试");
setRefreshing(false);
setTimeout(() => setRefreshResult(null), 5000);
}