first commit
This commit is contained in:
@@ -0,0 +1 @@
|
||||
from .base import *
|
||||
@@ -0,0 +1,23 @@
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
from app.models.enums import MethodType
|
||||
|
||||
|
||||
class BaseApi(BaseModel):
|
||||
path: str = Field(..., description="API路径", example="/api/v1/user/list")
|
||||
summary: str = Field("", description="API简介", example="查看用户列表")
|
||||
method: MethodType = Field(..., description="API方法", example="GET")
|
||||
tags: str = Field(..., description="API标签", example="User")
|
||||
|
||||
|
||||
class ApiCreate(BaseApi): ...
|
||||
|
||||
|
||||
class ApiUpdate(BaseApi):
|
||||
id: int
|
||||
|
||||
|
||||
class Paginate(BaseModel):
|
||||
page: int = Field(1, alias="pageNo", description="页码", example=1)
|
||||
page_size: int = Field(20, alias="pageSize", description="每页数量", example=20)
|
||||
|
||||
@@ -0,0 +1,164 @@
|
||||
# app/schemas/automation.py
|
||||
|
||||
from datetime import datetime
|
||||
from typing import List, Optional, Dict, Any
|
||||
from pydantic import BaseModel, Field
|
||||
from app.models.enums import TaskStatus, ScenarioScope, ActionType
|
||||
|
||||
# ----------------------------
|
||||
# Scenario Schemas
|
||||
# ----------------------------
|
||||
|
||||
class ScenarioBase(BaseModel):
|
||||
title: str = Field(..., max_length=255, description="场景标题")
|
||||
trigger: Dict[str, Any] = Field(..., description="触发条件(事件/时间)")
|
||||
actions: List[Dict[str, Any]] = Field(default_factory=list, description="执行动作模板列表")
|
||||
notes: Optional[str] = Field(None, description="备注")
|
||||
is_global: bool = Field(True, description="是否全局场景")
|
||||
owner_user_id: Optional[str] = Field(None, max_length=64, description="归属用户ID(非全局时有效)")
|
||||
enabled: bool = Field(True, description="是否启用")
|
||||
scope: ScenarioScope = Field(ScenarioScope.ALL, description="作用角色范围")
|
||||
|
||||
|
||||
class ScenarioCreate(ScenarioBase):
|
||||
pass
|
||||
|
||||
|
||||
class ScenarioUpdate(BaseModel):
|
||||
id: int = Field(..., description="场景ID")
|
||||
title: Optional[str] = Field(None, max_length=255)
|
||||
trigger: Optional[Dict[str, Any]] = None
|
||||
actions: Optional[List[Dict[str, Any]]] = None
|
||||
notes: Optional[str] = None
|
||||
is_global: Optional[bool] = None
|
||||
owner_user_id: Optional[str] = Field(None, max_length=64)
|
||||
enabled: Optional[bool] = None
|
||||
scope: Optional[ScenarioScope] = None
|
||||
|
||||
# model_config = {"extra": "forbid"} # 禁止传入未定义字段
|
||||
|
||||
|
||||
class ScenarioCopy(BaseModel):
|
||||
id: int = Field(..., description="场景ID")
|
||||
# model_config = {"extra": "forbid"} # 禁止传入未定义字段
|
||||
|
||||
|
||||
class ScenarioRead(ScenarioBase):
|
||||
id: int
|
||||
created_at: datetime
|
||||
updated_at: datetime
|
||||
|
||||
model_config = {"from_attributes": True}
|
||||
|
||||
|
||||
# ----------------------------
|
||||
# Task Schemas
|
||||
# ----------------------------
|
||||
|
||||
class TaskBase(BaseModel):
|
||||
title: str = Field(..., max_length=255, description="待办标题")
|
||||
# actions: List[Dict[str, Any]] = Field(default_factory=list, description="动作列表(动态组件渲染用)")
|
||||
event_data: Optional[Dict[str, Any]] = Field(default_factory=dict, description="事件数据")
|
||||
notes: Optional[str] = Field(None, description="备注")
|
||||
reason: Optional[str] = Field(None, description="触发原因")
|
||||
|
||||
# 关联字段
|
||||
source_scenario_id: Optional[int] = Field(None, description="来源场景ID")
|
||||
owner_user_id: Optional[str] = Field(None, max_length=64, description="归属用户ID")
|
||||
|
||||
# 分配与状态
|
||||
assignee_user_id: Optional[str] = Field(None, max_length=64, description="指派人用户ID")
|
||||
assignee_username: Optional[str] = Field(None, max_length=64, description="指派人用户名")
|
||||
status: TaskStatus = Field(TaskStatus.PENDING, description="任务状态")
|
||||
|
||||
# 自动化控制
|
||||
due_at: Optional[datetime] = Field(None, description="截止时间")
|
||||
auto_closeable: bool = Field(True, description="是否允许自动消除")
|
||||
closed_by: Optional[str] = Field(None, max_length=32, description="关闭方式: manual/auto/expired")
|
||||
|
||||
|
||||
class TaskCreate(TaskBase):
|
||||
pass
|
||||
|
||||
|
||||
class TaskUpdate(BaseModel):
|
||||
title: Optional[str] = Field(None, max_length=255)
|
||||
content: Optional[List[Dict[str, Any]]] = None
|
||||
notes: Optional[str] = None
|
||||
source_scenario_id: Optional[int] = None
|
||||
related_order_id: Optional[str] = Field(None, max_length=64)
|
||||
related_customer_id: Optional[str] = Field(None, max_length=64)
|
||||
group_id: Optional[str] = Field(None, max_length=64)
|
||||
assignee_user_id: Optional[str] = Field(None, max_length=64)
|
||||
assignee_username: Optional[str] = Field(None, max_length=64)
|
||||
status: Optional[TaskStatus] = None
|
||||
due_at: Optional[datetime] = None
|
||||
auto_closeable: Optional[bool] = None
|
||||
closed_by: Optional[str] = Field(None, max_length=32)
|
||||
completed_at: Optional[datetime] = None
|
||||
|
||||
# model_config = {"extra": "forbid"}
|
||||
|
||||
|
||||
class TaskRead(TaskBase):
|
||||
id: int
|
||||
created_at: datetime
|
||||
updated_at: datetime
|
||||
completed_at: Optional[datetime] = None
|
||||
|
||||
model_config = {"from_attributes": True}
|
||||
|
||||
|
||||
# ----------------------------
|
||||
# Action Schemas
|
||||
# ----------------------------
|
||||
|
||||
class ActionBase(BaseModel):
|
||||
type: Optional[ActionType] = Field(None, description="操作类型")
|
||||
detail: Dict[str, Any] = Field(default_factory=dict, description="操作详情")
|
||||
done: bool = Field(False, description="是否已完成")
|
||||
done_at: Optional[datetime] = Field(None, description="完成时间")
|
||||
result: Dict[str, Any] = Field(default_factory=dict, description="操作结果")
|
||||
userid: Optional[str] = Field(None, max_length=64, description="操作用户ID")
|
||||
username: Optional[str] = Field(None, max_length=64, description="操作用户名称")
|
||||
notes: Optional[str] = Field(None, description="操作备注")
|
||||
task_id: int = Field(..., description="所属任务ID")
|
||||
action_template_id: Optional[str] = Field(None, max_length=64, description="操作模板ID")
|
||||
|
||||
|
||||
class ActionCreate(ActionBase):
|
||||
pass
|
||||
|
||||
|
||||
class ActionUpdate(BaseModel):
|
||||
type: Optional[ActionType] = None
|
||||
detail: Optional[Dict[str, Any]] = None
|
||||
done: Optional[bool] = None
|
||||
done_at: Optional[datetime] = None
|
||||
result: Optional[Dict[str, Any]] = None
|
||||
userid: Optional[str] = Field(None, max_length=64)
|
||||
username: Optional[str] = Field(None, max_length=64)
|
||||
notes: Optional[str] = None
|
||||
task_id: Optional[int] = None
|
||||
action_template_id: Optional[str] = Field(None, max_length=64)
|
||||
|
||||
model_config = {"extra": "forbid"}
|
||||
|
||||
|
||||
class ActionRead(ActionBase):
|
||||
id: int
|
||||
created_at: datetime
|
||||
updated_at: datetime
|
||||
|
||||
model_config = {"from_attributes": True}
|
||||
|
||||
class NotifyAction(BaseModel):
|
||||
platform: str = Field(..., description="平台类型")
|
||||
webhook_url: str = Field(..., description="Webhook URL")
|
||||
template: str = Field(..., description="模板内容")
|
||||
need_at: bool = Field(False, description="是否需要@用户")
|
||||
|
||||
__meta_mapping__ = {
|
||||
"template": {"type": "text"}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
from typing import Any, Optional
|
||||
|
||||
from fastapi.responses import JSONResponse
|
||||
|
||||
|
||||
class Success(JSONResponse):
|
||||
def __init__(
|
||||
self,
|
||||
code: int = 200,
|
||||
msg: Optional[str] = "OK",
|
||||
data: Optional[Any] = None,
|
||||
**kwargs,
|
||||
):
|
||||
content = {"code": code, "msg": msg, "data": data}
|
||||
content.update(kwargs)
|
||||
super().__init__(content=content, status_code=code)
|
||||
|
||||
|
||||
class Fail(JSONResponse):
|
||||
def __init__(
|
||||
self,
|
||||
code: int = 400,
|
||||
msg: Optional[str] = None,
|
||||
data: Optional[Any] = None,
|
||||
**kwargs,
|
||||
):
|
||||
content = {"code": code, "msg": msg, "data": data}
|
||||
content.update(kwargs)
|
||||
super().__init__(content=content, status_code=code)
|
||||
|
||||
|
||||
class SuccessExtra(JSONResponse):
|
||||
def __init__(
|
||||
self,
|
||||
code: int = 200,
|
||||
msg: Optional[str] = None,
|
||||
data: Optional[Any] = None,
|
||||
total: int = 0,
|
||||
page: int = 1,
|
||||
page_size: int = 20,
|
||||
**kwargs,
|
||||
):
|
||||
content = {
|
||||
"code": code,
|
||||
"msg": msg,
|
||||
"data": data,
|
||||
"total": total,
|
||||
"page": page,
|
||||
"page_size": page_size,
|
||||
}
|
||||
content.update(kwargs)
|
||||
super().__init__(content=content, status_code=code)
|
||||
@@ -0,0 +1,48 @@
|
||||
from datetime import datetime
|
||||
from typing import Optional, Union
|
||||
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
|
||||
class BaseCodegen(BaseModel):
|
||||
name: Optional[str] = Field(description="名称")
|
||||
author: Optional[str] = Field(description="作者", default='')
|
||||
description: Optional[str] = Field(description="描述", default='')
|
||||
version: Optional[str] = Field(description="版本", default='')
|
||||
fields: Optional[Union[str, dict]] = Field(description="字段", default='{}')
|
||||
relations: Optional[Union[str, dict]] = Field(description="关系", default='{}')
|
||||
api: Optional[Union[str, dict]] = Field(description="API", default='{}')
|
||||
menu: Optional[Union[str, dict]] = Field(description="菜单", default='{}')
|
||||
|
||||
|
||||
class CodegenCreate(BaseCodegen):
|
||||
name: str = Field(description="名称")
|
||||
fields: str = Field(description="字段")
|
||||
|
||||
class CodegenUpdate(BaseModel):
|
||||
id: int = Field(example=1)
|
||||
name: str = Field(example="管理员")
|
||||
desc: str = Field("", example="管理员角色")
|
||||
|
||||
|
||||
class CodegenUpdateMenusApis(BaseModel):
|
||||
id: int
|
||||
menu_ids: list[int] = []
|
||||
api_infos: list[dict] = []
|
||||
|
||||
|
||||
class DatasourceInfo(BaseModel):
|
||||
id: int = Field(..., description="ID")
|
||||
tableName: Optional[str] = Field(..., description="名称")
|
||||
tableComment: Optional[str] = Field(..., description="注释")
|
||||
created_at: Optional[datetime]
|
||||
updated_at: Optional[datetime]
|
||||
|
||||
|
||||
class DatasourceCreate(DatasourceInfo):
|
||||
tableName: str = Field(..., description="名称")
|
||||
tableComment: str = Field(..., description="注释")
|
||||
|
||||
|
||||
class DatasourceUpdate(DatasourceInfo):
|
||||
id: int = Field(..., description="ID")
|
||||
@@ -0,0 +1,170 @@
|
||||
from pydantic import BaseModel, Field, field_validator
|
||||
from typing import Optional, Any
|
||||
from datetime import datetime # 如果需要 datetime 对象
|
||||
|
||||
# 如果你有 TimestampMixin,需要在这里导入或定义
|
||||
# class TimestampMixin(BaseModel):
|
||||
# created_at: Optional[datetime] = None
|
||||
# updated_at: Optional[datetime] = None
|
||||
|
||||
class CrmCustomerBase(BaseModel):
|
||||
# 保留 JSON 中存在的字段,并添加 alias
|
||||
customer_name: Optional[str] = Field(default=None, alias="customerName")
|
||||
province: Optional[str] = Field(default=None, alias="province")
|
||||
city: Optional[str] = Field(default=None, alias="city")
|
||||
area: Optional[str] = Field(default=None, alias="area")
|
||||
clinch_order: Optional[str] = Field(default=None, alias="clinchOrder")
|
||||
clinch_price: Optional[str] = Field(default=None, alias="clinchPrice")
|
||||
first_clinch_time: Optional[str] = Field(default=None, alias="firstClinchTime")
|
||||
last_clinch_time: Optional[str] = Field(default=None, alias="lastClinchTime")
|
||||
refund_order_times: Optional[str] = Field(default=None, alias="refundOrderTimes")
|
||||
refund_amount: Optional[str] = Field(default=None, alias="refundAmount")
|
||||
private_flag: Optional[int] = Field(default=None, alias="privateFlag") # JSON 中是 int
|
||||
touch_flag: Optional[int] = Field(default=None, alias="touchFlag") # JSON 中是 int
|
||||
open_id: Optional[str] = Field(default=None, alias="openId")
|
||||
xy_id: Optional[int] = Field(default=None, alias="xyId") # JSON 中是 int
|
||||
last_touch_time: Optional[str] = Field(default=None, alias="lastTouchTime")
|
||||
add_wechat_time: Optional[str] = Field(default=None, alias="addWeChatTime")
|
||||
mobile: Optional[str] = Field(default=None, alias="mobile")
|
||||
source: Optional[str] = Field(default=None, alias="source")
|
||||
we_chat_image: Optional[str] = Field(default=None, alias="weChatImage")
|
||||
cid: Optional[int] = Field(default=None, alias="cid") # JSON 中是 int
|
||||
last_trade_time: Optional[str] = Field(default=None, alias="lastTradeTime")
|
||||
private_jump: Optional[int] = Field(default=None, alias="privateJump") # JSON 中是 int
|
||||
lst_pay_ord_amt: Optional[float] = Field(default=None, alias="lstPayOrdAmt") # JSON 中是 float
|
||||
pay_avg_ord_amt_td: Optional[float] = Field(default=None, alias="payAvgOrdAmtTd") # JSON 中是 float
|
||||
refund_ord_rate_td: Optional[str] = Field(default=None, alias="refundOrdRateTd") # JSON 中是 string like '0.00%'
|
||||
touch_cnt_td: Optional[int] = Field(default=None, alias="touchCntTd") # JSON 中是 int
|
||||
pay_ord_day_cnt_1y: Optional[int] = Field(default=None, alias="payOrdDayCnt1y") # JSON 中是 int
|
||||
pay_same_item_max_cnt_td: Optional[int] = Field(default=None, alias="paySameItemMaxCntTd") # JSON 中是 int
|
||||
pay_diff_item_cnt_td: Optional[int] = Field(default=None, alias="payDiffItemCntTd") # JSON 中是 int
|
||||
pay_item_max_cnt_td: Optional[int] = Field(default=None, alias="payItemMaxCntTd") # JSON 中是 int
|
||||
user_type_90d: Optional[int] = Field(default=None, alias="userType90d") # JSON 中是 int
|
||||
# shop_id 和 shop_name 不在 JSON 中,但根据你的 Tortoise 模型定义,它们是 CrmCustomer 特有的,所以不加 alias
|
||||
shop_id: Optional[int] = Field(default=None) # 没有 alias,因为它在 JSON 中不存在
|
||||
shop_name: Optional[str] = Field(default=None) # 没有 alias,因为它在 JSON 中不存在
|
||||
|
||||
class Config:
|
||||
populate_by_name = True # 允许使用别名或字段名创建实例
|
||||
|
||||
class CrmCustomerCreate(CrmCustomerBase):
|
||||
pass
|
||||
|
||||
class CrmCustomerUpdate(BaseModel):
|
||||
# 这个模型的字段与 JSON 结构无关,保留原有定义
|
||||
customer_name: Optional[str] = None
|
||||
customer_remark: Optional[str] = None
|
||||
customer_desc: Optional[str] = None
|
||||
mobiles: Optional[list[str]] = None
|
||||
labels: Optional[list[dict[str, Any]]] = None
|
||||
follow_member_name: Optional[str] = None
|
||||
follow_member_mobile: Optional[str] = None
|
||||
follow_member_dept: Optional[str] = None
|
||||
source_tips: Optional[str] = None
|
||||
cus_channel: Optional[str] = None
|
||||
|
||||
class CrmCustomer(CrmCustomerBase):
|
||||
id: int = Field(alias="id") # JSON 中的 'id' 字段
|
||||
data_source: Optional[str] = None
|
||||
last_updated_from: Optional[str] = None
|
||||
# updated_at: Optional[datetime] = Field(default=None, alias="updatedAt") # 如果需要 datetime 对象
|
||||
updated_at: Optional[str] = Field(default=None, alias="updatedAt") # 使用 str 匹配 JSON 格式
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
populate_by_name = True
|
||||
|
||||
def convert_to_str(v) -> Optional[str]:
|
||||
"""将输入值转换为字符串"""
|
||||
if v is None:
|
||||
return v
|
||||
return str(v)
|
||||
|
||||
class CrmCustomerBase(BaseModel):
|
||||
# 对应 Tortoise 模型字段,并使用 JSON 中的键作为 alias
|
||||
cid: Optional[int] = Field(default=None, alias="cid", description="CID")
|
||||
customer_name: Optional[str] = Field(default=None, max_length=64, alias="customerName", description="客户名称")
|
||||
clinch_order: Optional[str] = Field(default=None, max_length=64, alias="clinchOrder", description="成交订单数")
|
||||
clinch_price: Optional[str] = Field(default=None, max_length=64, alias="clinchPrice", description="成交金额")
|
||||
first_clinch_time: Optional[datetime] = Field(default=None, alias="firstClinchTime", description="首次成交时间")
|
||||
last_clinch_time: Optional[datetime] = Field(default=None, alias="lastClinchTime", description="最后成交时间")
|
||||
refund_order_times: Optional[str] = Field(default=None, max_length=64, alias="refundOrderTimes", description="退款订单数")
|
||||
refund_amount: Optional[str] = Field(default=None, max_length=64, alias="refundAmount", description="退款金额")
|
||||
private_flag: Optional[bool] = Field(default=False, alias="privateFlag", description="是否私有")
|
||||
touch_flag: Optional[bool] = Field(default=False, alias="touchFlag", description="是否触达")
|
||||
open_id: Optional[str] = Field(default=None, max_length=64, alias="openId", description="微信openid")
|
||||
xy_id: Optional[int] = Field(default=None, alias="xyId", description="星云有客中的用户ID", index=True)
|
||||
last_touch_time: Optional[datetime] = Field(default=None, alias="lastTouchTime", description="最后触达时间")
|
||||
add_wechat_time: Optional[datetime] = Field(default=None, alias="addWeChatTime", description="添加微信时间")
|
||||
mobile: Optional[str] = Field(default=None, max_length=64, alias="mobile", description="手机号")
|
||||
source: Optional[str] = Field(default=None, max_length=64, alias="source", description="来源")
|
||||
we_chat_image: Optional[str] = Field(default=None, max_length=512, alias="weChatImage", description="微信头像")
|
||||
last_trade_time: Optional[datetime] = Field(default=None, alias="lastTradeTime", description="最后交易时间")
|
||||
private_jump: Optional[bool] = Field(default=False, alias="privateJump", description="是否跳转")
|
||||
lst_pay_ord_amt: Optional[str] = Field(default=None, alias="lstPayOrdAmt", description="最近一次支付金额")
|
||||
pay_avg_ord_amt_td: Optional[str] = Field(default=None, alias="payAvgOrdAmtTd", description="最近30天平均支付金额")
|
||||
refund_ord_rate_td: Optional[str] = Field(default=None, alias="refundOrdRateTd", description="最近30天退款订单数")
|
||||
touch_cnt_td: Optional[int] = Field(default=None, alias="touchCntTd", description="最近30天触达次数")
|
||||
pay_ord_day_cnt_1y: Optional[int] = Field(default=None, alias="payOrdDayCnt1y", description="最近一年支付订单数")
|
||||
pay_same_item_max_cnt_td: Optional[int] = Field(default=None, alias="paySameItemMaxCntTd", description="最近30天相同商品最大购买数量")
|
||||
pay_diff_item_cnt_td: Optional[int] = Field(default=None, alias="payDiffItemCntTd", description="最近30天不同商品购买数量")
|
||||
pay_item_max_cnt_td: Optional[int] = Field(default=None, alias="payItemMaxCntTd", description="最近30天最大购买商品数量")
|
||||
user_type_90d: Optional[int] = Field(default=None, alias="userType90d", description="最近90天用户类型")
|
||||
# shop_id 和 shop_name 在 JSON 中不存在,因此不设置 alias
|
||||
shop_id: Optional[int] = Field(default=None, description="店铺ID", index=True)
|
||||
shop_name: Optional[str] = Field(default=None, max_length=64, description="店铺名称")
|
||||
|
||||
@field_validator('lst_pay_ord_amt', 'pay_avg_ord_amt_td', 'refund_ord_rate_td', mode='before')
|
||||
def validate_and_convert_to_str(cls, v):
|
||||
return convert_to_str(v)
|
||||
|
||||
class Config:
|
||||
populate_by_name = True # 允许使用别名或字段名创建实例
|
||||
|
||||
class CrmCustomerCreate(CrmCustomerBase):
|
||||
pass
|
||||
|
||||
class CrmCustomerUpdate(BaseModel):
|
||||
# 保留原始定义(如果需要)
|
||||
customer_name: Optional[str] = None
|
||||
customer_remark: Optional[str] = None
|
||||
customer_desc: Optional[str] = None
|
||||
mobiles: Optional[list[str]] = None
|
||||
labels: Optional[list[dict[str, Any]]] = None
|
||||
follow_member_name: Optional[str] = None
|
||||
follow_member_mobile: Optional[str] = None
|
||||
follow_member_dept: Optional[str] = None
|
||||
source_tips: Optional[str] = None
|
||||
cus_channel: Optional[str] = None
|
||||
|
||||
|
||||
|
||||
class BaseCrmBindInfo(BaseModel):
|
||||
platform: Optional[str]= None
|
||||
customer_id: Optional[int]= None
|
||||
orderId: Optional[str]= None
|
||||
buyer_id: Optional[str]= None
|
||||
userid: Optional[str]= None
|
||||
name: Optional[str]= None
|
||||
nick_name: Optional[str]= None
|
||||
avatar: Optional[str]= None
|
||||
platform_id: Optional[str]= None
|
||||
need_confirm: Optional[bool]= None
|
||||
tenant_name: Optional[str]= None
|
||||
tenant_id: Optional[str]= None
|
||||
remark: Optional[str]= None
|
||||
extra: Optional[str]= None
|
||||
|
||||
|
||||
class CrmBindInfoCreate(BaseCrmBindInfo):
|
||||
id: Optional[int] = None
|
||||
pass
|
||||
|
||||
|
||||
class CrmBindInfoUpdate(BaseCrmBindInfo):
|
||||
id: int = Field(..., description="绑定信息ID")
|
||||
orderId: str = Field(..., description="订单ID")
|
||||
customer_id: int = Field(..., description="客户ID")
|
||||
name: str = Field(..., description="客户名称")
|
||||
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
from pydantic import BaseModel
|
||||
from typing import Optional, List, Dict, Any
|
||||
from datetime import datetime
|
||||
|
||||
class CustomerBase(BaseModel):
|
||||
customer_id: str
|
||||
customer_name: Optional[str] = None
|
||||
nick_name: Optional[str] = None
|
||||
head_url: Optional[str] = None
|
||||
gender: Optional[int] = None
|
||||
customer_remark: Optional[str] = None
|
||||
customer_desc: Optional[str] = None
|
||||
mobiles: Optional[List[str]] = None
|
||||
labels: Optional[List[Dict[str, Any]]] = None
|
||||
source_type: Optional[int] = None
|
||||
apply_mode: Optional[int] = None
|
||||
source_tips: Optional[str] = None
|
||||
source_room_id: Optional[str] = None
|
||||
source_room_name: Optional[str] = None
|
||||
source_room_image: Optional[str] = None
|
||||
follow_member_vid: str
|
||||
follow_member_name: Optional[str] = None
|
||||
follow_member_mobile: Optional[str] = None
|
||||
follow_member_dept: Optional[str] = None
|
||||
follow_member_avatar: Optional[str] = None
|
||||
create_time: Optional[int] = None
|
||||
update_time: Optional[int] = None
|
||||
tag_time: Optional[int] = None
|
||||
add_time: Optional[int] = None
|
||||
friend_flag: Optional[int] = None
|
||||
relation_flag: Optional[int] = None
|
||||
cus_channel: Optional[str] = None
|
||||
seq: Optional[str] = None
|
||||
kh_type: Optional[int] = None
|
||||
room_count: Optional[int] = 0
|
||||
user_count: Optional[int] = 0
|
||||
data_version: Optional[str] = None
|
||||
|
||||
class CustomerCreate(CustomerBase):
|
||||
pass
|
||||
|
||||
class CustomerUpdate(BaseModel):
|
||||
customer_name: Optional[str] = None
|
||||
customer_remark: Optional[str] = None
|
||||
customer_desc: Optional[str] = None
|
||||
mobiles: Optional[List[str]] = None
|
||||
labels: Optional[List[Dict[str, Any]]] = None
|
||||
follow_member_name: Optional[str] = None
|
||||
follow_member_mobile: Optional[str] = None
|
||||
follow_member_dept: Optional[str] = None
|
||||
source_tips: Optional[str] = None
|
||||
cus_channel: Optional[str] = None
|
||||
|
||||
class Customer(CustomerBase):
|
||||
id: int
|
||||
data_source: Optional[str] = None
|
||||
last_updated_from: Optional[str] = None
|
||||
updated_at: Optional[datetime] = None
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
@@ -0,0 +1,18 @@
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
|
||||
class BaseDept(BaseModel):
|
||||
name: str = Field(..., description="部门名称", example="研发中心")
|
||||
desc: str = Field("", description="备注", example="研发中心")
|
||||
order: int = Field(0, description="排序")
|
||||
parent_id: int = Field(0, description="父部门ID")
|
||||
|
||||
|
||||
class DeptCreate(BaseDept): ...
|
||||
|
||||
|
||||
class DeptUpdate(BaseDept):
|
||||
id: int
|
||||
|
||||
def update_dict(self):
|
||||
return self.model_dump(exclude_unset=True, exclude={"id"})
|
||||
@@ -0,0 +1,20 @@
|
||||
from datetime import datetime
|
||||
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
|
||||
class CredentialsSchema(BaseModel):
|
||||
username: str = Field(..., description="用户名称", example="admin")
|
||||
password: str = Field(..., description="密码", example="123456")
|
||||
|
||||
|
||||
class JWTOut(BaseModel):
|
||||
access_token: str
|
||||
username: str
|
||||
|
||||
|
||||
class JWTPayload(BaseModel):
|
||||
user_id: int
|
||||
username: str
|
||||
is_superuser: bool
|
||||
exp: datetime
|
||||
@@ -0,0 +1,52 @@
|
||||
from enum import StrEnum
|
||||
from typing import Optional
|
||||
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
|
||||
class MenuType(StrEnum):
|
||||
CATALOG = "catalog" # 目录
|
||||
MENU = "menu" # 菜单
|
||||
|
||||
|
||||
class BaseMenu(BaseModel):
|
||||
id: int
|
||||
name: str
|
||||
path: str
|
||||
remark: Optional[dict]
|
||||
menu_type: Optional[MenuType]
|
||||
icon: Optional[str]
|
||||
order: int
|
||||
parent_id: int
|
||||
is_hidden: bool
|
||||
component: str
|
||||
keepalive: bool
|
||||
redirect: Optional[str]
|
||||
children: Optional[list["BaseMenu"]]
|
||||
|
||||
|
||||
class MenuCreate(BaseModel):
|
||||
menu_type: MenuType = Field(default=MenuType.CATALOG.value)
|
||||
name: str = Field(example="用户管理")
|
||||
icon: Optional[str] = "ph:user-list-bold"
|
||||
path: str = Field(example="/system/user")
|
||||
order: Optional[int] = Field(example=1)
|
||||
parent_id: Optional[int] = Field(example=0, default=0)
|
||||
is_hidden: Optional[bool] = False
|
||||
component: str = Field(default="Layout", example="/system/user")
|
||||
keepalive: Optional[bool] = True
|
||||
redirect: Optional[str] = ""
|
||||
|
||||
|
||||
class MenuUpdate(BaseModel):
|
||||
id: int
|
||||
menu_type: Optional[MenuType] = Field(example=MenuType.CATALOG.value)
|
||||
name: Optional[str] = Field(example="用户管理")
|
||||
icon: Optional[str] = "ph:user-list-bold"
|
||||
path: Optional[str] = Field(example="/system/user")
|
||||
order: Optional[int] = Field(example=1)
|
||||
parent_id: Optional[int] = Field(example=0)
|
||||
is_hidden: Optional[bool] = False
|
||||
component: str = Field(example="/system/user")
|
||||
keepalive: Optional[bool] = False
|
||||
redirect: Optional[str] = ""
|
||||
@@ -0,0 +1,99 @@
|
||||
from typing import Optional
|
||||
from datetime import datetime
|
||||
|
||||
from pydantic import BaseModel, Field
|
||||
from app.models.enums import MsgType, ActionType
|
||||
|
||||
|
||||
class BaseMsg(BaseModel):
|
||||
hash_id: Optional[str] = Field(description="消息哈希ID")
|
||||
title: Optional[str] = Field(description="消息标题")
|
||||
content: Optional[str] = Field(description="消息内容")
|
||||
detail: Optional[str] = Field(default={}, description="消息详情")
|
||||
is_read: Optional[bool] = Field(default=False, description="是否已读")
|
||||
read_at: Optional[datetime] = Field(default=None, description="已读时间")
|
||||
is_delete: Optional[bool] = Field(default=False, description="是否已删除")
|
||||
delete_at: Optional[datetime] = Field(default=None, description="删除时间")
|
||||
is_send: Optional[bool] = Field(default=False, description="是否已发送")
|
||||
send_at: Optional[datetime] = Field(default=None, description="发送时间")
|
||||
type: Optional[MsgType] = Field(default=MsgType.SYSTEM, description="消息类型")
|
||||
owner_id: Optional[str] = Field(description="消息所有者ID")
|
||||
owner_name: Optional[str] = Field(description="消息所有者名称")
|
||||
|
||||
|
||||
class MsgCreate(BaseMsg):
|
||||
hash_id: str = Field(description="消息哈希ID")
|
||||
title: str = Field(description="消息标题")
|
||||
content: str = Field(description="消息内容")
|
||||
type: MsgType = Field(default=MsgType.SYSTEM, description="消息类型")
|
||||
owner_id: str = Field(description="消息所有者ID")
|
||||
owner_name: str = Field(description="消息所有者名称")
|
||||
|
||||
|
||||
class MsgUpdate(BaseModel):
|
||||
id: int
|
||||
is_read: Optional[bool] = Field(default=None, description="是否已读")
|
||||
is_delete: Optional[bool] = Field(default=None, description="是否已删除")
|
||||
is_send: Optional[bool] = Field(default=None, description="是否已发送")
|
||||
|
||||
class MsgNewOrder(BaseModel):
|
||||
type: Optional[MsgType] = Field(default=MsgType.NEW_ORDER, description="消息类型")
|
||||
order_id: str = Field(description="订单ID")
|
||||
order_status: str = Field(description="订单状态")
|
||||
is_refund: Optional[bool] = Field(default=False, alias="order_type", description="是否退款: 0-普通订单,1-退款订单")
|
||||
buyer_id: str = Field(description="买家ID")
|
||||
buyer_nick: str = Field(description="买家名称")
|
||||
|
||||
def __str__(self):
|
||||
return f'订单:{self.order_id} {self.order_status},买家:{self.buyer_nick or self.buyer_id} {"退款" if self.is_refund else ""}'
|
||||
|
||||
class MsgFilter(BaseModel):
|
||||
type: Optional[MsgType] = Field(default=None, description="消息类型")
|
||||
is_read: Optional[bool] = Field(default=None, description="是否已读")
|
||||
is_refund: Optional[bool] = Field(default=None, description="是否退款订单")
|
||||
|
||||
class BaseAction(BaseModel):
|
||||
type: Optional[ActionType] = Field(default=None, description="操作类型")
|
||||
detail: Optional[dict] = Field(default={}, description="操作详情")
|
||||
user_id: Optional[str] = Field(default=None, description="操作用户ID")
|
||||
user_name: Optional[str] = Field(default=None, description="操作用户名称")
|
||||
|
||||
class ActionCreate(BaseAction):
|
||||
done: Optional[bool] = Field(default=False, description="是否完成")
|
||||
type: ActionType = Field(description="操作类型")
|
||||
detail: dict = Field(description="操作详情")
|
||||
userid: str = Field(description="操作用户ID")
|
||||
username: str = Field(description="操作用户名称")
|
||||
|
||||
class ActionUpdate(BaseAction):
|
||||
id: int = Field(description="操作ID")
|
||||
|
||||
class FollowFormErp(BaseModel):
|
||||
order_id: str = Field(description="订单ID", alias="trade_no")
|
||||
order_title: str = Field(description="订单标题", alias="title")
|
||||
pay_time: str = Field(description="支付时间", alias="pay_time")
|
||||
pay_price: str = Field(description="支付金额", alias="price")
|
||||
remark: str = Field(description="erp额外备注", alias="remark")
|
||||
|
||||
shop_name: str = Field(description="店铺名称", alias="shop_name")
|
||||
|
||||
"""
|
||||
customer_id = fields.CharField(max_length=64, null=True, description="客户ID", index=True)
|
||||
customer_name = fields.CharField(max_length=64, null=True, description="客户名称", index=True)
|
||||
customer_taobao_id = fields.CharField(max_length=64, null=True, description="客户淘宝ID", index=True)
|
||||
|
||||
staff_id = fields.CharField(max_length=64, null=True, description="企微员工ID", index=True)
|
||||
staff_name = fields.CharField(max_length=64, null=True, description="企微员工名称", index=True)
|
||||
staff_time = fields.DatetimeField(null=True, description="添加时间", index=True)
|
||||
|
||||
designer_id = fields.CharField(max_length=64, null=True, description="设计师ID", index=True)
|
||||
designer_name = fields.CharField(max_length=64, null=True, description="设计师名称", index=True)
|
||||
|
||||
kefu_id = fields.CharField(max_length=64, null=True, description="淘宝客服ID", index=True)
|
||||
kefu_name = fields.CharField(max_length=64, null=True, description="淘宝客服名称", index=True)
|
||||
|
||||
"""
|
||||
|
||||
class FeishuEvent(BaseModel):
|
||||
challenge: str = Field(description="验证challenge")
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
from fastapi import Query, Request
|
||||
from tortoise.expressions import Q
|
||||
|
||||
|
||||
class QueryParams:
|
||||
def __init__(self,
|
||||
request: Request,
|
||||
page: int = Query(1, description="页码"),
|
||||
page_size: int = Query(10, description="每页数量"),
|
||||
):
|
||||
self.page = page
|
||||
self.page_size = page_size
|
||||
self.query_kwargs = dict(request.query_params)
|
||||
|
||||
self.q = Q()
|
||||
for key, value in self.query_kwargs.items():
|
||||
if key not in ['page', 'page_size']:
|
||||
# 使用 contains 方法实现包含查询
|
||||
self.q &= Q(**{f"{key}__contains": value})
|
||||
|
||||
def get_offset(self):
|
||||
return (self.page - 1) * self.page_size
|
||||
|
||||
def search_query(self, model, order=('-created_at',)):
|
||||
query = model.filter(self.q)
|
||||
return query, query.offset((self.page - 1) * self.page_size).limit(self.page_size).order_by(*order)
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
from datetime import datetime
|
||||
from typing import Optional
|
||||
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
|
||||
class BaseRole(BaseModel):
|
||||
id: int
|
||||
name: str
|
||||
desc: str = ""
|
||||
users: Optional[list] = []
|
||||
menus: Optional[list] = []
|
||||
apis: Optional[list] = []
|
||||
created_at: Optional[datetime]
|
||||
updated_at: Optional[datetime]
|
||||
|
||||
|
||||
class RoleCreate(BaseModel):
|
||||
name: str = Field(example="管理员")
|
||||
desc: str = Field("", example="管理员角色")
|
||||
|
||||
|
||||
class RoleUpdate(BaseModel):
|
||||
id: int = Field(example=1)
|
||||
name: str = Field(example="管理员")
|
||||
desc: str = Field("", example="管理员角色")
|
||||
|
||||
|
||||
class RoleUpdateMenusApis(BaseModel):
|
||||
id: int
|
||||
menu_ids: list[int] = []
|
||||
api_infos: list[dict] = []
|
||||
@@ -0,0 +1,75 @@
|
||||
from typing import Optional
|
||||
from typing import Dict, Any, Union
|
||||
from datetime import datetime
|
||||
|
||||
from pydantic import BaseModel, Field, ConfigDict
|
||||
from app.models.enums import TaskStatus, TaskType
|
||||
|
||||
class DecodeTaskParams(BaseModel):
|
||||
filename: str = Field(..., description="文件名")
|
||||
sheet_name: str = Field(..., description="工作表名称")
|
||||
decode_type: str = Field(..., description="解码类型")
|
||||
header: str = Field(..., description="解析列")
|
||||
model: Optional[str] = Field(None, description="模型名称")
|
||||
|
||||
class DecodeTaskResult(BaseModel):
|
||||
filename: str = Field(..., description="结果保存文件名")
|
||||
spend: float = Field(..., description="任务耗时")
|
||||
rows: int = Field(..., description="解析行数")
|
||||
|
||||
class TaskResponse(BaseModel):
|
||||
id: int
|
||||
name: str
|
||||
type: TaskType # ← Pydantic 会自动转为字符串
|
||||
params: dict
|
||||
status: TaskStatus # ← 同上
|
||||
result: Optional[dict]
|
||||
|
||||
class Config:
|
||||
from_attributes=True
|
||||
use_enum_values = True # ← 关键!将 Enum 转为值(如 'pending')
|
||||
# 或者在 Pydantic v2 中:
|
||||
# model_config = ConfigDict(use_enum_values=True)
|
||||
|
||||
class TaskModel(BaseModel):
|
||||
name: str
|
||||
type: TaskType # Enum: e.g., "decode", "upload", etc.
|
||||
params: Dict[str, Any] # 存储原始参数字典
|
||||
status: TaskStatus
|
||||
result: Optional[Dict[str, Any]] = None
|
||||
|
||||
@classmethod
|
||||
def create_decode_task(
|
||||
cls,
|
||||
name: str,
|
||||
params: DecodeTaskParams,
|
||||
status: TaskStatus = TaskStatus.PENDING
|
||||
) -> "TaskModel":
|
||||
"""创建解码任务的工厂方法"""
|
||||
return cls(
|
||||
name=name,
|
||||
type=TaskType.DECODE_ORDER,
|
||||
params=params.dict(),
|
||||
status=status
|
||||
)
|
||||
|
||||
def get_params(self) -> BaseModel:
|
||||
"""反序列化 params 为具体模型"""
|
||||
if self.type == TaskType.DECODE_ORDER:
|
||||
return DecodeTaskParams(**self.params)
|
||||
raise ValueError(f"Unknown task type: {self.type}")
|
||||
|
||||
def set_result(self, result: Union[DecodeTaskResult]) -> None:
|
||||
"""设置结果(自动序列化)"""
|
||||
if self.type == TaskType.DECODE_ORDER:
|
||||
self.result = result.dict()
|
||||
else:
|
||||
raise ValueError(f"Unsupported result for task type: {self.type}")
|
||||
|
||||
def get_result(self) -> Optional[BaseModel]:
|
||||
"""反序列化 result 为具体模型"""
|
||||
if self.result is None:
|
||||
return None
|
||||
if self.type == TaskType.DECODE_ORDER:
|
||||
return DecodeTaskResult(**self.result)
|
||||
raise ValueError(f"Unknown task type: {self.type}")
|
||||
@@ -0,0 +1,49 @@
|
||||
from datetime import datetime
|
||||
from typing import List, Optional
|
||||
|
||||
from pydantic import BaseModel, EmailStr, Field
|
||||
|
||||
|
||||
class BaseUser(BaseModel):
|
||||
id: int
|
||||
email: Optional[EmailStr] = None
|
||||
username: Optional[str] = None
|
||||
is_active: Optional[bool] = True
|
||||
is_superuser: Optional[bool] = False
|
||||
created_at: Optional[datetime]
|
||||
updated_at: Optional[datetime]
|
||||
last_login: Optional[datetime]
|
||||
roles: Optional[list] = []
|
||||
|
||||
|
||||
class UserCreate(BaseModel):
|
||||
email: EmailStr = Field(example="admin@qq.com")
|
||||
username: str = Field(example="admin")
|
||||
password: str = Field(example="123456")
|
||||
is_active: Optional[bool] = True
|
||||
is_superuser: Optional[bool] = False
|
||||
role_ids: Optional[List[int]] = []
|
||||
dept_id: Optional[int] = Field(0, description="部门ID")
|
||||
|
||||
def create_dict(self):
|
||||
return self.model_dump(exclude_unset=True, exclude={"role_ids"})
|
||||
|
||||
|
||||
class UserUpdate(BaseModel):
|
||||
id: int
|
||||
email: EmailStr
|
||||
username: str
|
||||
is_active: Optional[bool] = True
|
||||
is_superuser: Optional[bool] = False
|
||||
role_ids: Optional[List[int]] = []
|
||||
dept_id: Optional[int] = 0
|
||||
|
||||
class UserUpdateOnline(BaseModel):
|
||||
id: int
|
||||
email: EmailStr
|
||||
username: str
|
||||
|
||||
|
||||
class UpdatePassword(BaseModel):
|
||||
old_password: str = Field(description="旧密码")
|
||||
new_password: str = Field(description="新密码")
|
||||
@@ -0,0 +1,220 @@
|
||||
from datetime import datetime
|
||||
from typing import List, Optional, Union
|
||||
|
||||
from pydantic import BaseModel, EmailStr, Field
|
||||
|
||||
class BaseWeixinUser(BaseModel):
|
||||
userid: Optional[str] = None
|
||||
corp_id: Optional[str] = None
|
||||
vid: Optional[str] = None
|
||||
wx_id_hash: Optional[str] = None
|
||||
is_quit: Optional[bool] = None
|
||||
crmid: Optional[int] = None
|
||||
depart_ids: Optional[List[int]] = None
|
||||
position: Optional[str] = None
|
||||
role: Optional[str] = None
|
||||
realname: Optional[str] = None
|
||||
username: Optional[str] = None
|
||||
english_name: Optional[str] = None
|
||||
name: Optional[str] = None
|
||||
# 将所有属性映射为可选属性
|
||||
alias: Optional[str] = None
|
||||
avatar: Optional[str] = None
|
||||
department: Optional[int] = None
|
||||
mobile: Optional[str] = None
|
||||
email: Optional[EmailStr] = None
|
||||
gender: Optional[int] = None
|
||||
has_external_user_permit: Optional[bool] = None
|
||||
erpid: Optional[int] = None
|
||||
erp_name: Optional[str] = None
|
||||
crmid: Optional[int] = None
|
||||
crm_name: Optional[str] = None
|
||||
|
||||
class WeixinUserCreate(BaseWeixinUser):
|
||||
userid: str = Field(example="julia")
|
||||
name: str = Field(example='用户姓名')
|
||||
role: str = Field(example='用户角色')
|
||||
|
||||
|
||||
class WeixinUserUpdate(BaseModel):
|
||||
id: int
|
||||
crmid: Optional[int] = None
|
||||
erpid: Optional[int] = None
|
||||
is_quit: Optional[bool] = None
|
||||
|
||||
|
||||
class Member(BaseModel):
|
||||
userid: Optional[str] = Field(description="用户ID")
|
||||
name: Optional[str] = Field(description="用户姓名")
|
||||
type: Optional[int] = Field(description="用户类型: 1-外部成员, 2-内部成员")
|
||||
join_time: Optional[int] = Field(description="加入时间")
|
||||
# join_scene: Optional[int] = Field(description="加入场景")
|
||||
# unionid: Optional[str] = Field(description="微信UnionID")
|
||||
# invitor: Optional[dict] = Field(description="邀请人")
|
||||
group_nickname: Optional[str] = Field(description="群内昵称")
|
||||
|
||||
class BaseWeixinGroupChat(BaseModel):
|
||||
chat_id: Optional[str] = Field(description="企业微信中的群聊ID")
|
||||
name: Optional[str] = Field(description="群聊名称")
|
||||
admin_list: Optional[List[Member]] = Field(description="群聊管理员列表")
|
||||
create_time: Optional[int] = Field(description="群聊创建时间")
|
||||
owner: Optional[str] = Field(description="群聊群主")
|
||||
member_version: Optional[str] = Field(description="群聊成员版本")
|
||||
external_member_list: Optional[List[Member]] = Field(description="群聊外部成员列表")
|
||||
internal_member_list: Optional[List[Member]] = Field(description="群聊内部成员列表")
|
||||
|
||||
class WeixinGroupChatEvent(BaseWeixinGroupChat):
|
||||
external_user_count: Optional[int] = Field(description="群聊外部成员数量")
|
||||
internal_member_count: Optional[int] = Field(description="群聊内部成员数量")
|
||||
|
||||
__exclude_filter__ = ["admin_list", "member_version", "id"]
|
||||
|
||||
|
||||
class TriggerWeixinGroupChat(BaseModel):
|
||||
group_name: str = Field(alias="groupName", description="群聊名称")
|
||||
order_id: Optional[str] = Field(alias="orderId", description="订单ID", default=None)
|
||||
user_ids: Optional[List[str]] = Field(alias="userIds", description="群聊成员列表")
|
||||
external_user_ids: Optional[List[str]] = Field(alias="externalUserIds", description="群聊外部成员列表")
|
||||
|
||||
class WeixinGroupChatCreate(BaseWeixinGroupChat):
|
||||
pass
|
||||
|
||||
class WeixinGroupChatUpdate(BaseWeixinGroupChat):
|
||||
pass
|
||||
|
||||
class BaseWeixinGroupChatXingyun(BaseModel):
|
||||
xingyun_chat_id: Optional[int] = Field(alias="chatId")
|
||||
avatars: Optional[List[Union[str, None]]] = Field(alias="avatars")
|
||||
chat_id: Optional[str] = Field(alias="groupChatId")
|
||||
name: Optional[str] = Field(alias="chatName")
|
||||
admin_list: Optional[List[str]] = Field(alias="admins")
|
||||
create_time: Optional[int] = Field(alias="createTime")
|
||||
owner: Optional[str] = Field(alias="ownerName")
|
||||
member_version: Optional[str] = Field(default=None)
|
||||
external_member_list: Optional[List[str]] = Field(default=None)
|
||||
internal_member_list: Optional[List[str]] = Field(default=None)
|
||||
|
||||
class WeixinGroupChatXingyunCreate(BaseWeixinGroupChatXingyun):
|
||||
chat_id: str = Field(alias="groupChatId")
|
||||
name: str = Field(alias="chatName")
|
||||
xingyun_chat_id: int = Field(alias="chatId")
|
||||
|
||||
|
||||
class BaseWeixinCustomer(BaseModel):
|
||||
order_id: Optional[str] = Field(alias="orderId", description="订单ID", default=None)
|
||||
shop_name: Optional[str] = Field(alias="shopName", description="店铺名称", default=None)
|
||||
weixin_id: Optional[str] = Field(alias="weixinId", description="微信用户ID", default=None)
|
||||
weixin_name: Optional[str] = Field(alias="weixinName", description="微信用户名", default=None)
|
||||
weixin_unionid: Optional[str] = Field(alias="weixinUnionid", description="微信用户UnionID", default=None)
|
||||
weixin_avatar: Optional[str] = Field(alias="weixinAvatar", description="微信用户头像", default=None)
|
||||
xingyun_id: Optional[int] = Field(alias="xingyunId", description="星云用户ID", default=None)
|
||||
xingyun_sex: Optional[int] = Field(alias="xingyunSex", description="星云用户性别", default=None)
|
||||
xingyun_name: Optional[str] = Field(alias="xingyunName", description="星云用户名", default=None)
|
||||
xingyun_avatar: Optional[str] = Field(alias="xingyunAvatar", description="星云用户头像", default=None)
|
||||
xingyun_tags: Optional[list] = Field(alias="xingyunTags", description="星云用户标签", default=None)
|
||||
xingyun_external_userid: Optional[str] = Field(alias="xingyunExternalUserid", description="星云用户外部ID", default=None)
|
||||
xingyun_sync: Optional[bool] = Field(alias="xingyunSync", description="是否已同步到星云", default=False)
|
||||
taobao_id: Optional[str] = Field(alias="taobaoId", description="淘宝用户ID", default=None)
|
||||
taobao_name: Optional[str] = Field(alias="taobaoName", description="淘宝用户名", default=None)
|
||||
taobao_avatar: Optional[str] = Field(alias="taobaoAvatar", description="淘宝用户头像", default=None)
|
||||
need_confirm: Optional[bool] = Field(alias="needConfirm", description="是否需要确认", default=None)
|
||||
extra: Optional[dict] = Field(alias="extra", description="额外信息", default=None)
|
||||
|
||||
class WeixinCustomerCreate(BaseWeixinCustomer):
|
||||
pass
|
||||
|
||||
class WeixinCustomerUpdate(BaseWeixinCustomer):
|
||||
pass
|
||||
|
||||
class WeixinCustomerFilter(BaseModel):
|
||||
order_id: Optional[str] = Field(description="订单ID", default=None)
|
||||
has_order: Optional[bool] = Field(description="是否有订单", default=None)
|
||||
shop_name: Optional[str] = Field(description="店铺名称", default=None)
|
||||
# weixin_id: Optional[str] = Field(description="微信用户ID", default=None)
|
||||
# weixin_unionid: Optional[str] = Field(description="微信用户UnionID", default=None)
|
||||
# xingyun_id: Optional[int] = Field(description="星云用户ID", default=None)
|
||||
# xingyun_name: Optional[str] = Field(description="星云用户名", default=None)
|
||||
xingyun_tags: Optional[str] = Field(description="星云用户标签", default=None)
|
||||
xingyun_sync: Optional[bool] = Field(description="是否已同步到星云", default=False)
|
||||
# taobao_id: Optional[str] = Field(description="淘宝用户ID", default=None)
|
||||
# taobao_name: Optional[str] = Field(description="淘宝用户名", default=None)
|
||||
union_id: Optional[str] = Field(description="联合用户ID", default=None)
|
||||
union_name: Optional[str] = Field(description="联合用户名", default=None)
|
||||
|
||||
|
||||
class BaseWeixinCustomerXingyun(BaseModel):
|
||||
weixin_id: Optional[str] = Field(alias="external_userid", description="微信用户ID", default=None)
|
||||
weixin_name: Optional[str] = Field(alias="weixin_name", description="微信用户名", default=None)
|
||||
xingyun_id: Optional[int] = Field(alias="cid", description="星云用户ID")
|
||||
xingyun_name: Optional[str] = Field(alias="name", description="星云用户名")
|
||||
xingyun_avatar: Optional[str] = Field(alias="avatar", description="星云用户头像")
|
||||
xingyun_external_userid: Optional[str] = Field(alias="externalUserid", description="星云用户外部ID")
|
||||
xingyun_sex: Optional[int] = Field(alias="sex", description="星云用户性别", default=None)
|
||||
xingyun_tags: Optional[list] = Field(alias="tags", description="星云用户标签", default=None)
|
||||
# 移除这些字段,因为它们将被存储在 extra 中
|
||||
exclusive_member_info: Optional[dict] = Field(alias="exclusiveMemberInfo", description=" exclusiveMemberInfo", default=None)
|
||||
extra: Optional[dict] = Field(alias="extra", description="额外信息", default=None)
|
||||
|
||||
def transform_to_extra(self):
|
||||
new_obj = self.model_dump(exclude_unset=True, by_alias=True)
|
||||
extra = {
|
||||
'exclusive_member_info': new_obj.pop('exclusiveMemberInfo', None),
|
||||
}
|
||||
new_name = new_obj.get('name', None)
|
||||
if new_name: new_obj['weixin_name'] = new_name
|
||||
return self.__class__(**new_obj, extra=extra)
|
||||
|
||||
class WeixinCustomerXingyunCreate(BaseWeixinCustomerXingyun):
|
||||
pass
|
||||
|
||||
|
||||
class WeixinUserBindInfo(BaseModel):
|
||||
userid: str = Field(description="微信用户ID")
|
||||
username: Optional[str] = Field(description="微信用户名", alias="name")
|
||||
role: Optional[str] = Field(description="用户角色", default=None)
|
||||
erp_id: Optional[int] = Field(description="ERP用户ID", default=None)
|
||||
avatar: Optional[str] = Field(description="微信用户头像", default=None)
|
||||
taobao_id: Optional[str] = None
|
||||
|
||||
|
||||
class WeixinOrderBindInfo(BaseModel):
|
||||
userid: str = Field(description="微信用户ID")
|
||||
order_id: str = Field(description="订单ID")
|
||||
remark: Optional[str] = Field(description="企业微信向ERP同步订单时的备注", default=None)
|
||||
|
||||
class WeixinOrderRemark(BaseModel):
|
||||
order_id: str = Field(description="订单ID")
|
||||
remark: Optional[str] = Field(description="企业微信向ERP同步订单时的备注", default=None)
|
||||
|
||||
|
||||
class OrderUser(BaseModel):
|
||||
role: Optional[str] = Field(description="用户角色", default=None)
|
||||
taobao_id: Optional[str] = Field(description="旺旺名称", alias="id", default=None)
|
||||
taobao_name: Optional[str] = Field(description="旺旺名称", alias="name", default=None)
|
||||
userid: Optional[str] = Field(description="微信用户ID", default=None)
|
||||
|
||||
class BindOrderResultEvent(BaseModel):
|
||||
shop_name: Optional[str] = Field(description="店铺名称")
|
||||
price: Optional[int] = Field(description="订单金额")
|
||||
discount_fee: Optional[int] = Field(description="折扣金额")
|
||||
real_payment: Optional[int] = Field(description="实付金额")
|
||||
remark: Optional[str] = Field(description="企业微信向ERP同步订单时的备注", default=None)
|
||||
status_string: Optional[str] = Field(description="订单状态")
|
||||
pay_time: Optional[str] = Field(description="支付时间")
|
||||
users: Optional[List[OrderUser]] = Field(description="绑定的用户信息")
|
||||
|
||||
# __exclude_filter__ = ["member_version", "id"]
|
||||
|
||||
|
||||
class CustomerRepeatPurchaseEvent(BindOrderResultEvent):
|
||||
has_service_group: Optional[bool] = Field(description="是否有服务群", default=None)
|
||||
__exclude_filter__ = ["remark", "status_string", "pay_time"]
|
||||
|
||||
# CUSTOMER_SERVICE_ASSIGN_ORDER
|
||||
class CustomerAssignOrderEvent(BindOrderResultEvent):
|
||||
__exclude_filter__ = ["remark", "status_string"]
|
||||
|
||||
# CUSTOMER_SERVICE_ASSIGN_ORDER
|
||||
class CustomerRefundOrderEvent(BindOrderResultEvent):
|
||||
__exclude_filter__ = ["status_string"]
|
||||
|
||||
Reference in New Issue
Block a user