diff --git a/.dockerignore b/.dockerignore index df5bb9d..61b233d 100644 --- a/.dockerignore +++ b/.dockerignore @@ -15,3 +15,8 @@ build/ docker-compose.yml Dockerfile .dockerignore +android_app/ +data/ +logs/ +*.log +.env.local diff --git a/DEPLOY.md b/DEPLOY.md new file mode 100644 index 0000000..28e33fc --- /dev/null +++ b/DEPLOY.md @@ -0,0 +1,236 @@ +# 期货智析平台 - Docker 部署指南 + +## 📋 部署前准备 + +### 1. 环境要求 +- Docker Desktop for Windows(已安装并运行) +- Windows 10/11 专业版或家庭版(WSL2后端) +- 至少 2GB 可用内存 +- 至少 5GB 磁盘空间 + +### 2. 检查Docker状态 +```powershell +docker --version +docker-compose --version +``` + +## 🚀 快速部署 + +### 方法一:使用部署脚本(推荐) +1. 双击运行 `deploy.bat` +2. 等待自动完成构建和部署 +3. 访问 http://localhost:9600 + +### 方法二:手动部署 +```powershell +# 进入项目目录 +cd e:\docker_workspace\cobot2.0_WorkHorse\app\working\workspaces\default\share_data\project\market_data_colector_platform\buffer_platform + +# 停止旧容器 +docker-compose down + +# 构建镜像 +docker-compose build --no-cache + +# 启动服务 +docker-compose up -d +``` + +## 🌐 访问地址 + +部署成功后,可访问以下地址: + +| 服务 | 地址 | +|------|------| +| 主页 | http://localhost:9600 | +| 品种分析 | http://localhost:9600/futures-analysis | +| AI配置 | http://localhost:9600/ai-config | +| API文档 | http://localhost:9600/docs | +| 健康检查 | http://localhost:9600/api/v1/health | + +## 🛠️ 日常管理 + +### 使用管理脚本 +双击运行 `manage.bat`,可选择: +1. 启动服务 +2. 停止服务 +3. 重启服务 +4. 查看日志 +5. 查看状态 +6. 进入容器 +7. 清理资源 + +### 常用Docker命令 + +```powershell +# 查看容器状态 +docker-compose ps + +# 查看实时日志 +docker-compose logs -f + +# 查看最近100行日志 +docker-compose logs --tail=100 + +# 重启服务 +docker-compose restart + +# 停止服务 +docker-compose stop + +# 启动服务 +docker-compose start + +# 停止并删除容器(保留数据) +docker-compose down + +# 完全清理(包括数据卷) +docker-compose down -v + +# 进入容器bash +docker exec -it futures-buffer-platform /bin/bash + +# 查看容器资源使用 +docker stats futures-buffer-platform +``` + +## 📁 目录结构 + +``` +buffer_platform/ +├── data/ # SQLite数据库(自动创建) +├── logs/ # 日志文件(自动创建) +├── app/ +│ └── static/ # 前端静态文件 +├── docker-compose.yml # Docker编排配置 +├── Dockerfile # Docker镜像构建文件 +├── deploy.bat # 一键部署脚本 +└── manage.bat # 管理脚本 +``` + +## 🔧 配置说明 + +### 环境变量 + +在 `docker-compose.yml` 中可配置: + +| 变量 | 说明 | 默认值 | +|------|------|--------| +| BUFFER_DB_PATH | 数据库路径 | /app/data/buffer.db | +| BUFFER_HOST | 服务监听地址 | 0.0.0.0 | +| BUFFER_PORT | 服务端口 | 8600 | +| CACHE_TTL | 缓存过期时间(秒) | 300 | +| BUFFER_LOG_LEVEL | 日志级别 | INFO | +| MAX_WORKERS | 并发采集数 | 2 | +| TZ | 时区 | Asia/Shanghai | + +### 端口映射 + +- 宿主机端口:9600 +- 容器端口:8600 + +如需修改端口,编辑 `docker-compose.yml` 中的 `ports` 配置: +```yaml +ports: + - "你想要的端口:8600" +``` + +## 🔍 故障排查 + +### 1. 容器无法启动 +```powershell +# 查看详细日志 +docker-compose logs + +# 检查端口占用 +netstat -ano | findstr "9600" +``` + +### 2. 数据库问题 +```powershell +# 进入容器检查数据库 +docker exec -it futures-buffer-platform ls -la /app/data +``` + +### 3. 重新构建镜像 +```powershell +# 清理旧镜像 +docker-compose down +docker system prune -a + +# 重新构建 +docker-compose build --no-cache +docker-compose up -d +``` + +### 4. 查看健康状态 +```powershell +# 查看容器健康检查状态 +docker inspect --format='{{.State.Health.Status}}' futures-buffer-platform +``` + +## 🔄 更新部署 + +当代码有更新时: + +```powershell +# 方法一:使用部署脚本 +deploy.bat + +# 方法二:手动更新 +docker-compose down +docker-compose build --no-cache +docker-compose up -d +``` + +## 📊 监控和日志 + +### 实时日志 +```powershell +docker-compose logs -f buffer-platform +``` + +### 容器资源监控 +```powershell +docker stats futures-buffer-platform +``` + +### 日志位置 +- 容器内:/app/logs/ +- 宿主机:./logs/ + +## 🗄️ 数据备份 + +### 备份数据库 +```powershell +docker cp futures-buffer-platform:/app/data/buffer.db ./backup_buffer.db +``` + +### 恢复数据库 +```powershell +docker cp ./backup_buffer.db futures-buffer-platform:/app/data/buffer.db +docker-compose restart +``` + +## 🎯 生产环境建议 + +1. **修改默认端口**:避免端口冲突 +2. **配置日志轮转**:在docker-compose.yml中添加: + ```yaml + logging: + driver: "json-file" + options: + max-size: "10m" + max-file: "3" + ``` +3. **数据卷备份**:定期备份data目录 +4. **监控资源**:使用docker stats监控资源使用 +5. **设置重启策略**:已配置为 `unless-stopped` + +## 📞 技术支持 + +如遇问题,请检查: +1. Docker Desktop是否正常运行 +2. 端口9600是否被占用 +3. 查看容器日志:`docker-compose logs` +4. 检查健康状态:`docker-compose ps` diff --git a/app/api/auth.py b/app/api/auth.py new file mode 100644 index 0000000..9f898fb --- /dev/null +++ b/app/api/auth.py @@ -0,0 +1,149 @@ +""" +用户权限系统 - API路由 +""" +from fastapi import APIRouter, Depends, HTTPException, status +from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials +from sqlalchemy.orm import Session +from pydantic import BaseModel +from datetime import datetime +from typing import Optional + +from app.database import get_db +from app.user_models import User +from app import auth_service + +router = APIRouter(prefix="/auth", tags=["用户认证"]) +security = HTTPBearer() + + +# 请求模型 +class LoginRequest(BaseModel): + username: str + password: str + + +class LoginResponse(BaseModel): + success: bool + token: Optional[str] = None + user: Optional[dict] = None + message: Optional[str] = None + + +class UserInfo(BaseModel): + id: int + username: str + role: str + email: Optional[str] + + +# 登录接口 +@router.post("/login", response_model=LoginResponse) +def login(request: LoginRequest, db: Session = Depends(get_db)): + """用户登录""" + user = auth_service.authenticate_user(db, request.username, request.password) + + if not user: + return LoginResponse( + success=False, + message="用户名或密码错误" + ) + + # 创建会话 + token = auth_service.create_session(db, user.id) + auth_service.update_last_login(db, user) + + return LoginResponse( + success=True, + token=token, + user={ + "id": user.id, + "username": user.username, + "role": user.role, + "email": user.email + }, + message="登录成功" + ) + + +# 登出接口 +@router.post("/logout") +def logout(credentials: HTTPAuthorizationCredentials = Depends(security), db: Session = Depends(get_db)): + """用户登出""" + auth_service.invalidate_session(db, credentials.credentials) + return {"success": True, "message": "已登出"} + + +# 验证令牌接口 +@router.get("/verify") +def verify_token(credentials: HTTPAuthorizationCredentials = Depends(security), db: Session = Depends(get_db)): + """验证用户令牌""" + user = auth_service.validate_session(db, credentials.credentials) + + if not user: + raise HTTPException( + status_code=status.HTTP_401_UNAUTHORIZED, + detail="无效的会话令牌" + ) + + return { + "success": True, + "user": { + "id": user.id, + "username": user.username, + "role": user.role, + "email": user.email, + "last_login": user.last_login.isoformat() if user.last_login else None + } + } + + +# 获取当前用户信息 +@router.get("/me") +def get_current_user(credentials: HTTPAuthorizationCredentials = Depends(security), db: Session = Depends(get_db)): + """获取当前用户信息""" + user = auth_service.validate_session(db, credentials.credentials) + + if not user: + raise HTTPException( + status_code=status.HTTP_401_UNAUTHORIZED, + detail="无效的会话令牌" + ) + + return { + "id": user.id, + "username": user.username, + "role": user.role, + "email": user.email, + "is_active": user.is_active, + "created_at": user.created_at.isoformat(), + "last_login": user.last_login.isoformat() if user.last_login else None + } + + +# 依赖注入:验证用户已登录 +def get_current_user_dependency(credentials: HTTPAuthorizationCredentials = Depends(security), db: Session = Depends(get_db)): + """依赖注入:获取当前用户""" + user = auth_service.validate_session(db, credentials.credentials) + if not user: + raise HTTPException( + status_code=status.HTTP_401_UNAUTHORIZED, + detail="请先登录" + ) + return user + + +# 依赖注入:仅管理员可访问 +def require_admin(credentials: HTTPAuthorizationCredentials = Depends(security), db: Session = Depends(get_db)): + """依赖注入:验证管理员权限""" + user = auth_service.validate_session(db, credentials.credentials) + if not user: + raise HTTPException( + status_code=status.HTTP_401_UNAUTHORIZED, + detail="请先登录" + ) + if user.role != 'admin': + raise HTTPException( + status_code=status.HTTP_403_FORBIDDEN, + detail="需要管理员权限" + ) + return user diff --git a/app/auth_service.py b/app/auth_service.py new file mode 100644 index 0000000..d4e3399 --- /dev/null +++ b/app/auth_service.py @@ -0,0 +1,129 @@ +""" +用户权限系统 - 认证服务 +""" +import hashlib +import secrets +from datetime import datetime, timedelta +from typing import Optional +from sqlalchemy.orm import Session +from app.user_models import User, Session as UserSession + + +# 密码加密工具 +def hash_password(password: str) -> str: + """对密码进行哈希加密""" + salt = secrets.token_hex(16) + pwd_hash = hashlib.sha256((salt + password).encode()).hexdigest() + return f"{salt}${pwd_hash}" + + +def verify_password(password: str, hashed: str) -> bool: + """验证密码""" + try: + salt, pwd_hash = hashed.split('$') + return hashlib.sha256((salt + password).encode()).hexdigest() == pwd_hash + except: + return False + + +def generate_token() -> str: + """生成会话令牌""" + return secrets.token_urlsafe(32) + + +# 用户操作 +def create_user(db: Session, username: str, password: str, email: str = None, role: str = 'user') -> User: + """创建新用户""" + user = User( + username=username, + password_hash=hash_password(password), + email=email, + role=role, + is_active=True + ) + db.add(user) + db.commit() + db.refresh(user) + return user + + +def authenticate_user(db: Session, username: str, password: str) -> Optional[User]: + """验证用户登录""" + user = db.query(User).filter(User.username == username).first() + if not user: + return None + if not user.is_active: + return None + if not verify_password(password, user.password_hash): + return None + return user + + +def update_last_login(db: Session, user: User): + """更新最后登录时间""" + user.last_login = datetime.utcnow() + db.commit() + + +# 会话操作 +def create_session(db: Session, user_id: int, expires_hours: int = 24) -> str: + """创建用户会话""" + token = generate_token() + session = UserSession( + user_id=user_id, + token=token, + expires_at=datetime.utcnow() + timedelta(hours=expires_hours), + is_valid=True + ) + db.add(session) + db.commit() + return token + + +def validate_session(db: Session, token: str) -> Optional[User]: + """验证会话令牌""" + session = db.query(UserSession).filter( + UserSession.token == token, + UserSession.is_valid == True, + UserSession.expires_at > datetime.utcnow() + ).first() + + if not session: + return None + + user = db.query(User).filter(User.id == session.user_id).first() + if not user or not user.is_active: + return None + + return user + + +def invalidate_session(db: Session, token: str): + """使会话失效(登出)""" + session = db.query(UserSession).filter(UserSession.token == token).first() + if session: + session.is_valid = False + db.commit() + + +def cleanup_expired_sessions(db: Session): + """清理过期会话""" + db.query(UserSession).filter( + UserSession.expires_at < datetime.utcnow() + ).update({"is_valid": False}) + db.commit() + + +# 默认用户创建 +def create_default_admin(db: Session): + """创建默认管理员账户""" + admin = db.query(User).filter(User.username == 'lxy_root').first() + if not admin: + create_user( + db=db, + username='lxy_root', + password='admin123', + email='admin@system.local', + role='admin' + ) + print("✓ 默认管理员账户已创建: lxy_root / admin123") diff --git a/app/main.py b/app/main.py index 6108c76..28947b2 100644 --- a/app/main.py +++ b/app/main.py @@ -5,14 +5,15 @@ import logging from contextlib import asynccontextmanager from pathlib import Path -from fastapi import FastAPI +from fastapi import FastAPI, Request from fastapi.middleware.cors import CORSMiddleware from fastapi.staticfiles import StaticFiles -from fastapi.responses import FileResponse +from fastapi.responses import FileResponse, RedirectResponse from app.database import engine, Base +from app.user_models import Base as UserBase from app.config import HOST, PORT, LOG_LEVEL -from app.api import data, tasks, config, futures_analysis, ai_config +from app.api import data, tasks, config, futures_analysis, ai_config, auth from app.services.scheduler import start_scheduler, stop_scheduler # 配置日志 @@ -29,15 +30,25 @@ async def lifespan(app: FastAPI): # 启动时:建表 + 启动调度器 logger.info("创建数据库表...") Base.metadata.create_all(bind=engine) + UserBase.metadata.create_all(bind=engine) + from app.analysis_db import init_analysis_db init_analysis_db() logger.info("期货智析数据库初始化完成") + + # 创建默认管理员账户 + from app.database import SessionLocal + from app import auth_service + db = SessionLocal() + try: + auth_service.create_default_admin(db) + finally: + db.close() logger.info("启动定时调度器...") start_scheduler() # 恢复已启用的任务 - from app.database import SessionLocal from app.services.cache import list_tasks from app.services.scheduler import add_job @@ -81,12 +92,29 @@ STATIC_DIR.mkdir(parents=True, exist_ok=True) app.mount("/static", StaticFiles(directory=str(STATIC_DIR), html=True), name="static") +# 登录页面(无需认证) +@app.get("/login") +def login_page(): + """登录页面""" + return FileResponse(str(STATIC_DIR / "login.html")) + + +# 角色选择页面(需要管理员权限) +@app.get("/role-select") +def role_select_page(): + """角色选择页面""" + return FileResponse(str(STATIC_DIR / "role_select.html")) + + +# 品种配置管理页面(需要管理员权限) @app.get("/ui") def ui_page(): """品种配置管理页面""" return FileResponse(str(STATIC_DIR / "index.html")) + # 注册路由 +app.include_router(auth.router, prefix="/api/v1") app.include_router(data.router, prefix="/api/v1") app.include_router(tasks.router, prefix="/api/v1") app.include_router(config.router, prefix="/api/v1") @@ -111,13 +139,11 @@ def health(): return {"status": "ok", "service": "market-data-buffer"} +# 根路径重定向到登录页 @app.get("/") def root(): - return { - "message": "数据缓冲平台 API", - "docs": "/docs", - "health": "/api/v1/health", - } + """根路径重定向到登录页""" + return RedirectResponse(url="/login") if __name__ == "__main__": diff --git a/app/static/login.html b/app/static/login.html new file mode 100644 index 0000000..d7de0af --- /dev/null +++ b/app/static/login.html @@ -0,0 +1,284 @@ + + + + + + 登录 - 期货智析系统 + + + +
+
+ +

期货智析

+ +
+ +
+ +
+
+ + +
+ +
+ + +
+ + +
+ + +
+ + + + diff --git a/app/static/role_select.html b/app/static/role_select.html new file mode 100644 index 0000000..958d72b --- /dev/null +++ b/app/static/role_select.html @@ -0,0 +1,215 @@ + + + + + + 选择入口 - 期货智析系统 + + + +
+
+

◈ 欢迎使用期货智析系统

+

请选择您要进入的模块

+ +
+ +
+ +
📊
+
品种分析
+
+ 智能期货品种分析工具,提供K线图表、技术指标、AI智能分析等功能,帮助您做出更明智的交易决策。 +
+
进入分析 →
+
+ + +
⚙️
+
系统管理
+
+ 管理系统配置、品种设置、定时任务、数据源配置等后台管理功能。 +
+
进入管理 →
+
+
+ + +
+ + + + diff --git a/app/user_models.py b/app/user_models.py new file mode 100644 index 0000000..9b33f3d --- /dev/null +++ b/app/user_models.py @@ -0,0 +1,38 @@ +""" +用户权限系统 - 数据库模型 +""" +from datetime import datetime +from sqlalchemy import Column, Integer, String, Boolean, DateTime +from app.database import Base + + +class User(Base): + """用户表""" + __tablename__ = "users" + + id = Column(Integer, primary_key=True, autoincrement=True) + username = Column(String(50), unique=True, nullable=False, index=True) + password_hash = Column(String(255), nullable=False) + email = Column(String(100), unique=True, nullable=True) + role = Column(String(20), nullable=False, default='user') # 'admin' 或 'user' + is_active = Column(Boolean, default=True) + created_at = Column(DateTime, default=datetime.utcnow) + last_login = Column(DateTime, nullable=True) + + def __repr__(self): + return f"" + + +class Session(Base): + """用户会话表""" + __tablename__ = "sessions" + + id = Column(Integer, primary_key=True, autoincrement=True) + user_id = Column(Integer, nullable=False, index=True) + token = Column(String(255), unique=True, nullable=False, index=True) + created_at = Column(DateTime, default=datetime.utcnow) + expires_at = Column(DateTime, nullable=False) + is_valid = Column(Boolean, default=True) + + def __repr__(self): + return f"" diff --git a/backup.bat b/backup.bat new file mode 100644 index 0000000..472230a --- /dev/null +++ b/backup.bat @@ -0,0 +1,41 @@ +@echo off +chcp 65001 >nul +setlocal enabledelayedexpansion + +echo ======================================== +echo 数据库备份工具 +echo ======================================== +echo. + +REM 生成备份文件名 +set BACKUP_DATE=%date:~0,4%%date:~5,2%%date:~8,2%_%time:~0,2%%time:~3,2%%time:~6,2% +set BACKUP_DATE=%BACKUP_DATE: =0% +set BACKUP_FILE=buffer_backup_%BACKUP_DATE%.db + +echo 备份文件: %BACKUP_FILE% +echo. + +REM 停止服务 +echo [1/3] 停止服务... +docker-compose stop +echo ✓ 服务已停止 + +REM 备份数据库 +echo [2/3] 备份数据库... +if exist "E:\docker_workspace\futures_datas\buffer.db" ( + copy "E:\docker_workspace\futures_datas\buffer.db" "E:\docker_workspace\futures_datas\%BACKUP_FILE%" + echo ✓ 数据库已备份到: E:\docker_workspace\futures_datas\%BACKUP_FILE% +) else ( + echo ✗ 数据库文件不存在 +) + +REM 启动服务 +echo [3/3] 启动服务... +docker-compose start +echo ✓ 服务已启动 + +echo. +echo ======================================== +echo 备份完成! +echo ======================================== +pause diff --git a/data/buffer.db b/data/buffer.db index d767e54..ac31c43 100644 Binary files a/data/buffer.db and b/data/buffer.db differ diff --git a/deploy.bat b/deploy.bat new file mode 100644 index 0000000..d31f8e7 --- /dev/null +++ b/deploy.bat @@ -0,0 +1,55 @@ +@echo off +chcp 65001 >nul +echo ==================================== +echo 期货智析平台 - Docker 部署脚本 +echo ==================================== +echo. + +echo [1/4] 检查Docker环境... +docker --version >nul 2>&1 +if errorlevel 1 ( + echo [错误] 未检测到Docker,请先安装Docker Desktop + pause + exit /b 1 +) +echo [√] Docker已安装 + +echo. +echo [2/4] 停止并清理旧容器... +docker-compose down +echo [√] 清理完成 + +echo. +echo [3/4] 构建Docker镜像... +docker-compose build --no-cache +if errorlevel 1 ( + echo [错误] 镜像构建失败 + pause + exit /b 1 +) +echo [√] 镜像构建完成 + +echo. +echo [4/4] 启动Docker容器... +docker-compose up -d +if errorlevel 1 ( + echo [错误] 容器启动失败 + pause + exit /b 1 +) + +echo. +echo ==================================== +echo 部署完成! +echo ==================================== +echo. +echo 访问地址: http://localhost:9600 +echo 品种分析: http://localhost:9600/futures-analysis +echo API文档: http://localhost:9600/docs +echo 健康检查: http://localhost:9600/api/v1/health +echo. +echo 查看日志: docker-compose logs -f +echo 停止服务: docker-compose down +echo 重启服务: docker-compose restart +echo. +pause diff --git a/docker-compose.yml b/docker-compose.yml index e3bf4c8..14dc9b7 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -16,11 +16,14 @@ services: - CACHE_TTL=300 - BUFFER_LOG_LEVEL=INFO - MAX_WORKERS=2 + - TZ=Asia/Shanghai volumes: # 数据持久化 - SQLite数据库 - - E:\docker_workspace\futures_datas:/app/data + - ./data:/app/data + # 静态文件(开发模式,生产环境应该打包到镜像中) + - ./app/static:/app/app/static # 日志持久化(可选) - - E:\docker_workspace\futures_datas\logs:/app/logs + - ./logs:/app/logs healthcheck: test: ["CMD", "curl", "-f", "http://localhost:8600/api/v1/health"] interval: 30s diff --git a/manage.bat b/manage.bat new file mode 100644 index 0000000..08a352a --- /dev/null +++ b/manage.bat @@ -0,0 +1,98 @@ +@echo off +chcp 65001 >nul +echo ==================================== +echo 期货智析平台 - Docker 管理脚本 +echo ==================================== +echo. +echo 请选择操作: +echo 1. 启动服务 +echo 2. 停止服务 +echo 3. 重启服务 +echo 4. 查看日志 +echo 5. 查看状态 +echo 6. 进入容器 +echo 7. 清理资源 +echo 0. 退出 +echo. +set /p choice=请输入选项 (0-7): + +if "%choice%"=="1" goto start +if "%choice%"=="2" goto stop +if "%choice%"=="3" goto restart +if "%choice%"=="4" goto logs +if "%choice%"=="5" goto status +if "%choice%"=="6" goto shell +if "%choice%"=="7" goto clean +if "%choice%"=="0" goto end +goto menu + +:start +echo. +echo [启动服务...] +docker-compose up -d +echo. +echo 服务已启动!访问 http://localhost:9600 +pause +goto menu + +:stop +echo. +echo [停止服务...] +docker-compose stop +echo. +echo 服务已停止! +pause +goto menu + +:restart +echo. +echo [重启服务...] +docker-compose restart +echo. +echo 服务已重启! +pause +goto menu + +:logs +echo. +echo [查看日志 - 按Ctrl+C退出] +docker-compose logs -f --tail=100 +goto menu + +:status +echo. +echo [服务状态] +docker-compose ps +echo. +echo [容器资源使用] +docker stats --no-stream futures-buffer-platform +pause +goto menu + +:shell +echo. +echo [进入容器...] +docker exec -it futures-buffer-platform /bin/bash +goto menu + +:clean +echo. +echo [警告] 这将停止并删除容器,但保留数据卷 +set /p confirm=确认继续? (y/n): +if /i not "%confirm%"=="y" goto menu +echo. +echo [清理资源...] +docker-compose down +echo. +echo 资源已清理! +pause +goto menu + +:menu +cls +goto start + +:end +echo. +echo 再见! +exit diff --git a/start.bat b/start.bat new file mode 100644 index 0000000..b879f5e --- /dev/null +++ b/start.bat @@ -0,0 +1,25 @@ +@echo off +chcp 65001 >nul +echo ======================================== +echo 启动期货智析缓冲平台 +echo ======================================== +echo. + +docker-compose start +echo. + +echo 等待服务启动... +timeout /t 3 /nobreak >nul + +echo. +echo ======================================== +echo 访问地址: +echo 品种分析页面: http://localhost:9600/futures-analysis +echo 配置管理页面: http://localhost:9600/ui +echo AI配置页面: http://localhost:9600/ai-config +echo API文档: http://localhost:9600/docs +echo ======================================== +echo. + +docker-compose ps +pause diff --git a/stop.bat b/stop.bat new file mode 100644 index 0000000..8342b08 --- /dev/null +++ b/stop.bat @@ -0,0 +1,13 @@ +@echo off +chcp 65001 >nul +echo ======================================== +echo 停止期货智析缓冲平台 +echo ======================================== +echo. + +docker-compose stop +echo. +echo ✓ 服务已停止 +echo. +echo 使用 start.bat 重新启动服务 +pause