Files
liuwenxinandClaude Code 1625907380 feat(business): 客户评级等级映射配置接口(区间重叠判定/名称唯一)
- 判定=按 sort_order 升序首个 min_score≤总分,边界相邻不算重叠
- 新增同样执行重叠判定(判定表语义下插出重叠即脏配置)
- 等级配置无下游引用(评级为纯计算器,对照表 #25),允许清空

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-10-13 12:01:47 +08:00

75 lines
2.9 KiB
Python

"""客户评级等级配置接口(需求 2.2.5)。
评级计算器的等级映射判定表:判定按 sort_order 升序取首个 min_score ≤ 总分
的等级,max_score 仅展示。区间合法(0≤min≤max≤100)与互不重叠由后端校验
—— 前端表单只是展示约束,后端校验是唯一防线。
列表不分页全量返回:等级映射是判定表,数量个位数,分页无意义。
业务数据属业务操作,登录用户即可访问(区别于系统管理模块的 AdminUser);
写操作经 RequestMetaDep 带入请求元信息,由 service 层写入操作日志。
"""
from typing import Annotated
from fastapi import APIRouter, Depends, Path
from app.api.deps import DbSession, RequestMetaDep, get_current_user
from app.core.response import ApiResponse, ok
from app.models import User
from app.schemas.rating import RatingGradeCreateIn, RatingGradeOut, RatingGradeUpdateIn
from app.services import rating_service
CurrentUser = Annotated[User, Depends(get_current_user)]
router = APIRouter(prefix="/rating-grades", tags=["客户评级"])
@router.get("", response_model=ApiResponse[list[RatingGradeOut]], summary="评级等级列表")
def list_grades(
session: DbSession,
_: CurrentUser,
) -> ApiResponse[list[RatingGradeOut]]:
"""全量等级列表,按判定顺序(sort_order 升序)返回,不分页。"""
return ok(rating_service.list_grades(session))
@router.post("", response_model=ApiResponse[RatingGradeOut], summary="新增评级等级")
def create_grade(
session: DbSession,
current_user: CurrentUser,
payload: RatingGradeCreateIn,
meta: RequestMetaDep,
) -> ApiResponse[RatingGradeOut]:
"""新增评级等级。区间须 0≤min≤max≤100 且与既有等级不重叠。"""
return ok(
rating_service.create_grade(session, payload, operator=current_user, meta=meta),
message="评级等级已创建",
)
@router.put("/{grade_id}", response_model=ApiResponse[RatingGradeOut], summary="编辑评级等级")
def update_grade(
session: DbSession,
current_user: CurrentUser,
grade_id: Annotated[int, Path(ge=1)],
payload: RatingGradeUpdateIn,
meta: RequestMetaDep,
) -> ApiResponse[RatingGradeOut]:
"""编辑评级等级(全量替换)。区间须合法且与其他等级不重叠。"""
return ok(
rating_service.update_grade(session, grade_id, payload, operator=current_user, meta=meta),
message="已保存",
)
@router.delete("/{grade_id}", response_model=ApiResponse[None], summary="删除评级等级")
def delete_grade(
session: DbSession,
current_user: CurrentUser,
grade_id: Annotated[int, Path(ge=1)],
meta: RequestMetaDep,
) -> ApiResponse[None]:
"""物理删除评级等级(等级表无下游引用,允许清空,理由见 service 说明)。"""
rating_service.delete_grade(session, grade_id, operator=current_user, meta=meta)
return ok(message="评级等级已删除")