feat: 宇之然平台 v2.0 - 完整重构版

核心功能:
- 新增 JWT 认证系统,支持管理员登录/登出
- 前后端合并为单一 FastAPI 应用 (端口 8001)
- 系统概览页:6 个统计卡片,点击跳转筛选
- 选题管理页:批量操作 (刷新/创作/优化),时间列展示
- 系统日志页:整合日志查看功能
- 用户管理页:管理员可创建/删除用户
- 移动端适配:响应式布局,底部导航栏
- 标题居中显示

技术改进:
- 添加 generated_at 字段支持创作时间记录
- 状态更新时自动同步 updated_at
- 所有 API 路由添加 JWT 认证保护
- 前端 authFetch 封装自动附加 Token
- 升级 FastAPI 0.136, Pydantic 2.13 等依赖

修复:
- 修复 API 500 错误 (数据库列缺失)
- 修复 formatRelativeTime 未定义错误
- 修复登录 Token 存储和自动附加逻辑
This commit is contained in:
lt
2026-04-27 10:01:33 +08:00
parent 3cb2df51c8
commit 2bd3c83cf5
14 changed files with 1241 additions and 645 deletions
+93 -9
View File
@@ -1,7 +1,51 @@
from pydantic import BaseModel
from pydantic import BaseModel, ConfigDict
from datetime import datetime, date
from typing import Optional, List, Dict, Any
class AuditLogBase(BaseModel):
user_id: Optional[int] = None
username: str
action: str
resource_type: Optional[str] = None
resource_id: Optional[str] = None
details: Optional[Dict[str, Any]] = None
ip_address: Optional[str] = None
user_agent: Optional[str] = None
created_at: Optional[datetime] = None
class AuditLogResponse(AuditLogBase):
id: int
model_config = ConfigDict(from_attributes=True)
class UserBase(BaseModel):
username: str
role: str = "user"
class UserCreate(UserBase):
password: str
class UserUpdate(BaseModel):
username: Optional[str] = None
password: Optional[str] = None
role: Optional[str] = None
class UserResponse(UserBase):
id: int
created_at: Optional[datetime] = None
model_config = ConfigDict(from_attributes=True)
class LoginRequest(BaseModel):
username: str
password: str
class TokenResponse(BaseModel):
token: str
role: str
user: UserResponse
class TopicBase(BaseModel):
id: str
title: str
@@ -11,14 +55,14 @@ class TopicBase(BaseModel):
compliance_score: Optional[int] = None
ready_at: Optional[date] = None
published_at: Optional[date] = None
generated_at: Optional[datetime] = None
platform_urls: Optional[Dict[str, str]] = None
class TopicResponse(TopicBase):
created_at: Optional[datetime] = None
updated_at: Optional[datetime] = None
class Config:
from_attributes = True
model_config = ConfigDict(from_attributes=True)
class ArticleBase(BaseModel):
id: str
@@ -30,8 +74,7 @@ class ArticleBase(BaseModel):
created_at: Optional[datetime] = None
class ArticleResponse(ArticleBase):
class Config:
from_attributes = True
model_config = ConfigDict(from_attributes=True)
class SystemStatus(BaseModel):
total_topics: int
@@ -40,14 +83,55 @@ class SystemStatus(BaseModel):
today_articles: int
compliance_rate: float
last_optimization: Optional[datetime] = None
execution_time: Optional[float] = None # 任务执行耗时(秒)
execution_time: Optional[float] = None
class OptimizationRequest(BaseModel):
topic_ids: Optional[List[str]] = None # None表示全部
topic_ids: Optional[List[str]] = None
class PublishRequest(BaseModel):
topic_id: str
platform_urls: Dict[str, str] # {"zhihu": "...", "wechat": "...", "xiaohongshu": "..."}
platform_urls: Dict[str, str]
class PublishActionRequest(BaseModel):
action: str
platform: Optional[str] = None
status: str
operator: Optional[str] = None
description: Optional[str] = None
suggestion: Optional[str] = None
url: Optional[str] = None
error_msg: Optional[str] = None
class PublishRecordResponse(BaseModel):
id: int
topic_id: str
platform: str
action: str
status: str
operator: Optional[str] = None
description: Optional[str] = None
suggestion: Optional[str] = None
url: Optional[str] = None
error_msg: Optional[str] = None
created_at: datetime
model_config = ConfigDict(from_attributes=True)
class BatchPublishRequest(BaseModel):
date: str # YYYY-MM-DD
date: str
class AuditLogResponse(BaseModel):
id: int
user_id: Optional[int] = None
username: str
action: str
resource_type: Optional[str] = None
resource_id: Optional[str] = None
details: Optional[Dict[str, Any]] = None
ip_address: Optional[str] = None
user_agent: Optional[str] = None
created_at: datetime
model_config = ConfigDict(from_attributes=True)