refactor: 统一项目中状态字段类型为数字类型

这是一个大规模的类型对齐优化:
1.  将多处字符串类型的status字段统一改为数字类型,包括前后端接口定义、数据模型、页面组件
2.  重构编排节点相关的命名和注释,统一改为"节点类型"替代"编排节点类型"
3.  移除了过时的忘记密码相关接口和模板代码
4.  优化搜索栏组件,支持展开仅显示次要字段
5.  调整部分接口参数和路由逻辑,对齐前后端参数格式
This commit is contained in:
zhangtao
2026-06-23 00:30:40 +08:00
parent 134337b502
commit 414d5c80c3
95 changed files with 561 additions and 883 deletions
@@ -37,9 +37,7 @@ from .schema import (
AutoLoginTokenSchema,
AutoLoginUserSchema,
CaptchaOutSchema,
ForgotPasswordSchema,
LoginWithTenantsSchema,
ResetPasswordWithTokenSchema,
SelectTenantOutSchema,
SelectTenantSchema,
TenantOptionSchema,
@@ -50,7 +48,6 @@ from .service import (
AutoLoginService,
CaptchaService,
LoginService,
PasswordResetService,
TenantRegisterService,
)
@@ -314,29 +311,4 @@ async def tenant_register_controller(
return SuccessResponse(data=result, msg=result.message)
@AuthRouter.post(
"/forgot-password",
summary="忘记密码",
response_model=ResponseSchema[str],
)
async def forgot_password_controller(
data: ForgotPasswordSchema,
redis: Annotated[Redis, Depends(redis_getter)],
db: Annotated[AsyncSession, Depends(db_getter)],
) -> JSONResponse:
msg = await PasswordResetService.forgot_password(redis=redis, db=db, email=data.email)
return SuccessResponse(data=msg, msg="邮件已发送")
@AuthRouter.post(
"/reset-password",
summary="重置密码",
response_model=ResponseSchema[str],
)
async def reset_password_controller(
data: ResetPasswordWithTokenSchema,
redis: Annotated[Redis, Depends(redis_getter)],
db: Annotated[AsyncSession, Depends(db_getter)],
) -> JSONResponse:
msg = await PasswordResetService.reset_password_with_token(redis=redis, db=db, token=data.token, new_password=data.new_password)
return SuccessResponse(data=msg, msg="密码已重置")
@@ -86,16 +86,3 @@ class TenantRegisterOutSchema(BaseModel):
package: str | None = Field(default=None, description="开通套餐")
trial_end: str = Field(..., description="试用到期日")
message: str = Field(default="注册成功", description="提示信息")
class ForgotPasswordSchema(BaseModel):
"""忘记密码:提交邮箱,接收重置邮件"""
email: str = Field(..., max_length=128, description="注册时使用的邮箱")
class ResetPasswordWithTokenSchema(BaseModel):
"""通过邮件链接重置密码"""
token: str = Field(..., min_length=1, description="密码重置令牌")
new_password: str = Field(..., min_length=6, max_length=128, description="新密码")
@@ -1,6 +1,5 @@
import json
import secrets
import uuid
from datetime import datetime, timedelta
from typing import NewType
@@ -847,104 +846,3 @@ class TenantRegisterService:
body_html=html_body,
)
logger.info(f"欢迎邮件已发送至 {to_email}")
class PasswordResetService:
"""PRD §4.6 忘记密码:邮箱重置令牌 + 密码更新"""
RESET_TOKEN_PREFIX = "pwd_reset:"
TOKEN_EXPIRE_SECONDS = 1800 # 30 分钟
@classmethod
async def forgot_password(cls, redis: Redis, db: AsyncSession, email: str) -> str:
"""忘记密码:根据邮箱查找用户,生成重置令牌并尝试发送邮件。"""
from sqlalchemy import select
from app.api.v1.module_system.user.model import UserModel
stmt = select(UserModel).where(
UserModel.email == email,
UserModel.is_deleted.is_(False),
)
result = await db.execute(stmt)
user = result.scalar_one_or_none()
if not user:
logger.info(f"忘记密码:邮箱 {email} 未注册,静默返回")
return "若邮箱已注册,重置邮件已发送"
token = secrets.token_urlsafe(32)
key = f"{cls.RESET_TOKEN_PREFIX}{token}"
await RedisCURD(redis).set(key=key, value=str(user.id), expire=cls.TOKEN_EXPIRE_SECONDS)
try:
await cls._send_reset_email(email, user.username, token)
except Exception:
logger.warning(f"密码重置邮件发送失败: {email}")
return "若邮箱已注册,重置邮件已发送"
@classmethod
async def reset_password_with_token(cls, redis: Redis, db: AsyncSession, token: str, new_password: str) -> str:
"""使用令牌重置密码。校验令牌 → 更新密码 → 删除令牌。"""
from app.api.v1.module_system.user.model import UserModel
key = f"{cls.RESET_TOKEN_PREFIX}{token}"
user_id_str = await RedisCURD(redis).get(key)
if not user_id_str:
raise CustomException(msg="重置链接已失效,请重新申请")
try:
user_id = int(user_id_str)
except (ValueError, TypeError):
await RedisCURD(redis).delete(key)
raise CustomException(msg="无效的重置链接")
user = await db.get(UserModel, user_id)
if not user or user.is_deleted:
await RedisCURD(redis).delete(key)
raise CustomException(msg="用户不存在")
user.password = PwdUtil.hash_password(new_password)
await db.commit()
await RedisCURD(redis).delete(key)
logger.info(f"用户 {user.username}(id={user_id}) 密码已重置")
return "密码重置成功,请使用新密码登录"
@classmethod
async def _send_reset_email(cls, to_email: str, username: str, token: str) -> None:
"""发送密码重置邮件。"""
from app.api.v1.module_platform.email.crud import EmailConfigCRUD
from app.core.base_schema import AuthSchema
from app.core.database import async_db_session
from app.utils.email_util import render_template_file, send_email
async with async_db_session() as _db:
cfg = await EmailConfigCRUD(AuthSchema(db=_db, check_data_scope=False)).get_active_default()
if not cfg:
logger.info("无可用 SMTP 配置,跳过重置邮件")
return
reset_url = f"{getattr(settings, 'SITE_URL', '')}/reset-password?token={token}"
html_body = render_template_file("emails/reset_password.jinja2", {
"username": username,
"reset_url": reset_url,
"expire_minutes": cls.TOKEN_EXPIRE_SECONDS // 60,
})
await send_email(
smtp_host=cfg.smtp_host,
smtp_port=cfg.smtp_port,
smtp_user=cfg.smtp_user,
smtp_password=cfg.smtp_password,
use_tls=cfg.use_tls,
from_name=cfg.from_name,
to_email=to_email,
to_name=username,
subject="密码重置 - FastapiAdmin",
body_html=html_body,
)
logger.info(f"密码重置邮件已发送至 {to_email}")