178 lines
9.4 KiB
Python
178 lines
9.4 KiB
Python
"""CRM 线索管理 Pydantic Schemas"""
|
||
|
||
from typing import List, Optional
|
||
|
||
from pydantic import BaseModel, ConfigDict, Field
|
||
|
||
|
||
# ── 线索列表查询 ──────────────────────────────────────────────────
|
||
|
||
|
||
class ClueListBody(BaseModel):
|
||
model_config = ConfigDict(populate_by_name=True)
|
||
|
||
page: int = Field(default=1, ge=1, description="页码")
|
||
pageSize: int = Field(default=10, ge=1, le=500, description="每页条数")
|
||
keyword: Optional[str] = Field(default=None, description="搜索关键词(线索名称/手机号)")
|
||
search_keyword: Optional[str] = Field(
|
||
default=None, alias="searchKeyword", description="快速搜索关键词(与 keyword 等价)"
|
||
)
|
||
clue_name: Optional[str] = Field(default=None, alias="clueName", description="线索名称")
|
||
company: Optional[str] = Field(default=None, description="公司名称")
|
||
mobile: Optional[str] = Field(default=None, description="手机号")
|
||
source: Optional[str] = Field(default=None, description="线索来源")
|
||
level: Optional[str] = Field(default=None, description="线索级别")
|
||
status: Optional[str] = Field(default=None, description="线索状态")
|
||
industry: Optional[str] = Field(default=None, description="所属行业")
|
||
park_area: Optional[str] = Field(default=None, alias="parkArea", description="所在园区")
|
||
owner_user_id: Optional[str] = Field(default=None, alias="ownerUserId", description="负责人ID")
|
||
view_type: Optional[str] = Field(
|
||
default=None, alias="viewType", description="视图类型(mine/all/toFollow/todayNew/converted)"
|
||
)
|
||
view_mode: Optional[str] = Field(default=None, alias="viewMode", description="视图模式(mine/all)")
|
||
create_time_range: Optional[List[str]] = Field(
|
||
default=None, alias="createTimeRange", description="创建时间范围 [start, end]"
|
||
)
|
||
begin_time: Optional[str] = Field(default=None, alias="beginTime", description="创建时间起")
|
||
end_time: Optional[str] = Field(default=None, alias="endTime", description="创建时间止")
|
||
|
||
|
||
# ── 线索新增/编辑 ──────────────────────────────────────────────────
|
||
|
||
ids: Optional[List[str]] = Field(default=None, description="导出指定ID列表")
|
||
columns: Optional[List[str]] = Field(default=None, description="导出列(前端 visibleColumns)")
|
||
|
||
|
||
class ClueCreateBody(BaseModel):
|
||
model_config = ConfigDict(populate_by_name=True)
|
||
|
||
clue_name: str = Field(..., alias="clueName", min_length=1, max_length=100, description="线索名称")
|
||
mobile: str = Field(..., min_length=1, max_length=20, description="手机号")
|
||
company: Optional[str] = Field(default=None, max_length=200, description="公司名称")
|
||
customer_type: Optional[str] = Field(default=None, alias="customerType", max_length=20, description="客户类型")
|
||
telephone: Optional[str] = Field(default=None, max_length=30, description="座机")
|
||
email: Optional[str] = Field(default=None, max_length=100, description="邮箱")
|
||
title: Optional[str] = Field(default=None, max_length=10, description="称谓")
|
||
position: Optional[str] = Field(default=None, max_length=50, description="职位")
|
||
source: str = Field(..., max_length=20, description="线索来源")
|
||
level: Optional[str] = Field(default="unrated", max_length=10, description="线索级别")
|
||
industry: Optional[str] = Field(default=None, max_length=50, description="所属行业")
|
||
park_area: Optional[str] = Field(default=None, alias="parkArea", max_length=100, description="所在园区")
|
||
province: Optional[str] = Field(default=None, max_length=50, description="省份")
|
||
city: Optional[str] = Field(default=None, max_length=50, description="城市")
|
||
district: Optional[str] = Field(default=None, max_length=50, description="区县")
|
||
address: Optional[str] = Field(default=None, max_length=255, description="详细地址")
|
||
website: Optional[str] = Field(default=None, max_length=500, description="网站")
|
||
intent_products: Optional[str] = Field(
|
||
default=None, alias="intentProducts", max_length=500, description="意向产品"
|
||
)
|
||
expect_time: Optional[str] = Field(default=None, alias="expectTime", description="预计购买时间")
|
||
budget: Optional[str] = Field(default=None, max_length=20, description="预算")
|
||
requirement: Optional[str] = Field(default=None, description="需求描述")
|
||
owner_user_id: Optional[str] = Field(default=None, alias="ownerUserId", description="负责人ID")
|
||
next_time: Optional[str] = Field(default=None, alias="nextTime", description="下次联系时间")
|
||
remark: Optional[str] = Field(default=None, max_length=512, description="备注")
|
||
|
||
|
||
class ClueUpdateBody(ClueCreateBody):
|
||
id: str = Field(..., min_length=1, description="线索ID")
|
||
|
||
|
||
# ── 线索操作 ──────────────────────────────────────────────────
|
||
|
||
|
||
class ClueDeleteBody(BaseModel):
|
||
model_config = ConfigDict(populate_by_name=True)
|
||
|
||
ids: List[str] = Field(..., min_length=1, description="线索ID列表")
|
||
|
||
|
||
class ClueAssignBody(BaseModel):
|
||
model_config = ConfigDict(populate_by_name=True)
|
||
|
||
ids: List[str] = Field(..., min_length=1, description="线索ID列表")
|
||
owner_user_id: str = Field(..., alias="ownerUserId", description="新负责人ID")
|
||
remark: Optional[str] = Field(default=None, description="分配说明")
|
||
|
||
|
||
class ClueConvertBody(BaseModel):
|
||
model_config = ConfigDict(populate_by_name=True)
|
||
|
||
id: str = Field(..., min_length=1, description="线索ID")
|
||
customer_name: Optional[str] = Field(default=None, alias="customerName", description="客户名称")
|
||
customer_type: Optional[str] = Field(default=None, alias="customerType", description="客户类型")
|
||
contact_name: Optional[str] = Field(default=None, alias="contactName", description="联系人姓名")
|
||
contact_mobile: Optional[str] = Field(default=None, alias="contactMobile", description="联系人手机号")
|
||
remark: Optional[str] = Field(default=None, description="转化说明")
|
||
|
||
|
||
class ClueStatusBody(BaseModel):
|
||
model_config = ConfigDict(populate_by_name=True)
|
||
|
||
id: str = Field(..., min_length=1, description="线索ID")
|
||
status: str = Field(..., max_length=20, description="目标状态")
|
||
|
||
|
||
class ClueLevelBody(BaseModel):
|
||
model_config = ConfigDict(populate_by_name=True)
|
||
|
||
ids: List[str] = Field(..., min_length=1, description="线索ID列表")
|
||
level: str = Field(..., max_length=10, description="目标级别")
|
||
|
||
|
||
class ClueInvalidBody(BaseModel):
|
||
model_config = ConfigDict(populate_by_name=True)
|
||
|
||
id: Optional[str] = Field(default=None, description="线索ID")
|
||
ids: Optional[List[str]] = Field(default=None, description="线索ID列表")
|
||
remark: Optional[str] = Field(default=None, description="作废原因")
|
||
|
||
|
||
# ── 跟进记录 ──────────────────────────────────────────────────
|
||
|
||
|
||
class ClueFollowListBody(BaseModel):
|
||
model_config = ConfigDict(populate_by_name=True)
|
||
|
||
clue_id: str = Field(..., alias="clueId", description="线索ID")
|
||
page: int = Field(default=1, ge=1, description="页码")
|
||
pageSize: int = Field(default=10, ge=1, le=500, description="每页条数")
|
||
|
||
|
||
class ClueFollowCreateBody(BaseModel):
|
||
model_config = ConfigDict(populate_by_name=True)
|
||
|
||
clue_id: str = Field(..., alias="clueId", description="线索ID")
|
||
follow_type: str = Field(..., alias="followType", max_length=20, description="跟进方式")
|
||
follow_content: str = Field(..., alias="followContent", description="跟进内容")
|
||
next_time: Optional[str] = Field(default=None, alias="nextTime", description="下次联系时间")
|
||
attachments: Optional[str] = Field(default=None, max_length=1000, description="附件URL(逗号分隔)")
|
||
remark: Optional[str] = Field(default=None, description="备注")
|
||
|
||
|
||
class ClueFollowDeleteBody(BaseModel):
|
||
model_config = ConfigDict(populate_by_name=True)
|
||
|
||
ids: List[str] = Field(..., min_length=1, description="跟进记录ID列表")
|
||
|
||
|
||
class ClueFollowUpdateBody(BaseModel):
|
||
model_config = ConfigDict(populate_by_name=True)
|
||
|
||
id: str = Field(..., min_length=1, description="跟进记录ID")
|
||
follow_type: Optional[str] = Field(default=None, alias="followType", description="跟进方式")
|
||
follow_content: Optional[str] = Field(default=None, alias="followContent", description="跟进内容")
|
||
next_time: Optional[str] = Field(default=None, alias="nextTime", description="下次联系时间")
|
||
attachments: Optional[str] = Field(default=None, max_length=1000, description="附件URL(逗号分隔)")
|
||
remark: Optional[str] = Field(default=None, description="备注")
|
||
|
||
|
||
class ClueStatisticsBody(BaseModel):
|
||
model_config = ConfigDict(populate_by_name=True)
|
||
|
||
begin_time: Optional[str] = Field(default=None, alias="beginTime", description="开始日期")
|
||
end_time: Optional[str] = Field(default=None, alias="endTime", description="结束日期")
|
||
owner_user_id: Optional[str] = Field(default=None, alias="ownerUserId", description="负责人ID")
|
||
time_unit: Optional[str] = Field(default="day", alias="timeUnit", description="趋势粒度 day/week/month")
|
||
type: Optional[str] = Field(default=None, description="趋势粒度别名")
|