ems-core v1.0.0: Standard EMS platform core

Shared backend + frontend for multi-customer EMS deployments.
- 12 enterprise modules: quota, cost, charging, maintenance, analysis, etc.
- 120+ API endpoints, 37 database tables
- Customer config mechanism (CUSTOMER env var + YAML config)
- Collectors: Modbus TCP, MQTT, HTTP API, Sungrow iSolarCloud
- Frontend: React 19 + Ant Design + ECharts + Three.js
- Infrastructure: Redis cache, rate limiting, aggregation engine

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Du Wenbo
2026-04-04 18:14:11 +08:00
commit 92ec910a13
227 changed files with 39179 additions and 0 deletions

View File

@@ -0,0 +1,53 @@
from datetime import datetime, timezone
from fastapi import APIRouter, Depends, HTTPException, Request, status
from fastapi.security import OAuth2PasswordRequestForm
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select
from pydantic import BaseModel
from app.core.database import get_db
from app.core.security import verify_password, create_access_token, hash_password
from app.core.deps import get_current_user
from app.models.user import User
from app.services.audit import log_audit
router = APIRouter(prefix="/auth", tags=["认证"])
class Token(BaseModel):
access_token: str
token_type: str = "bearer"
user: dict
class RegisterRequest(BaseModel):
username: str
password: str
full_name: str | None = None
email: str | None = None
phone: str | None = None
@router.post("/login", response_model=Token)
async def login(request: Request, form: OAuth2PasswordRequestForm = Depends(), db: AsyncSession = Depends(get_db)):
result = await db.execute(select(User).where(User.username == form.username))
user = result.scalar_one_or_none()
if not user or not verify_password(form.password, user.hashed_password):
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="用户名或密码错误")
if not user.is_active:
raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="账号已禁用")
user.last_login = datetime.now(timezone.utc)
token = create_access_token({"sub": str(user.id), "role": user.role})
client_ip = request.client.host if request.client else None
await log_audit(db, user.id, "login", "auth", detail=f"用户 {user.username} 登录", ip_address=client_ip)
return Token(
access_token=token,
user={"id": user.id, "username": user.username, "full_name": user.full_name, "role": user.role}
)
@router.get("/me")
async def get_me(user: User = Depends(get_current_user)):
return {
"id": user.id, "username": user.username, "full_name": user.full_name,
"email": user.email, "phone": user.phone, "role": user.role, "is_active": user.is_active,
}