feat(customer): 客户评级并入客户管理并落库
- customers 表新增 rating_score/rating_time(V13 迁移 + V10 SQL + init-dev 同步)
- 新端点 PUT /customers/{id}/rating:评分是档案属性,只存总分与评级时间(五项明细不落库)
- 列表排序 order_by=rating_score,未评分客户升序/降序都垫底,id desc 兜底稳定分页
- 前端 RatingCalculatorDialog 并入客户管理(评分列 + 评级计算按钮),删除独立页与路由
- 测试:评级保存/越界/排序垫底 3 例,test_customers.py 18 passed;schema 同步 216 passed
This commit is contained in:
1 parent
b9781f7d3f
commit
32b7940067
17 files changed
+917
-512
No files matched your search
@@ -1,6 +1,7 @@
|
||||
"""客户管理的请求/响应模型(需求 2.1.3)。"""
|
||||
|
||||
from datetime import datetime
|
||||
from typing import Literal
|
||||
|
||||
from pydantic import BaseModel, ConfigDict, Field
|
||||
|
||||
@@ -28,6 +29,8 @@ class CustomerOut(BaseModel):
|
||||
owner_personnel_id: int | None = None
|
||||
owner_personnel_name: str | None = None
|
||||
remark: str | None = None
|
||||
rating_score: int | None = None
|
||||
rating_time: datetime | None = None
|
||||
|
||||
|
||||
class CustomerCreateIn(BaseModel):
|
||||
@@ -90,13 +93,32 @@ class CustomerUpdateIn(BaseModel):
|
||||
|
||||
|
||||
class CustomerQuery(PageQuery):
|
||||
"""客户列表查询条件(字段名蛇形直出,与前端 api 封装同名对应)。"""
|
||||
"""客户列表查询条件(字段名蛇形直出,与前端 api 封装同名对应)。
|
||||
|
||||
排序用 ``Literal`` 白名单而不是自由字符串:``order_by`` 直接拼进
|
||||
``ORDER BY``,自由值等于把注入面开到排序键上;客户列表只有两个
|
||||
有意义的排序键,白名单足够。
|
||||
"""
|
||||
|
||||
keyword: str | None = Field(
|
||||
default=None, max_length=64, description="公司名称或客户负责人,模糊匹配"
|
||||
)
|
||||
customer_type: str | None = Field(default=None, max_length=32, description="客户分类筛选")
|
||||
owner_personnel_id: int | None = Field(default=None, ge=1, description="归属人员ID筛选")
|
||||
order_by: Literal["id", "rating_score"] = Field(
|
||||
default="id", description="排序键:id 建档序 / rating_score 评级总分"
|
||||
)
|
||||
order: Literal["asc", "desc"] = Field(default="desc", description="排序方向")
|
||||
|
||||
|
||||
class CustomerRatingIn(BaseModel):
|
||||
"""保存客户评级入参(评级计算器「保存评分」)。
|
||||
|
||||
score 是五项之和的整数(0-100);五项明细不落库(评级记录只存总分,
|
||||
见对照表 #25 的定位:评分是档案属性而非审计事件)。
|
||||
"""
|
||||
|
||||
score: int = Field(ge=0, le=100, description="评级总分(0-100 整数)")
|
||||
|
||||
|
||||
class CustomerOwnershipIn(BaseModel):
|
||||
|
||||
Reference in new issue
Block a user