189 lines
7.8 KiB
Python
189 lines
7.8 KiB
Python
# -*- coding: utf-8 -*-
|
||
"""
|
||
DRF 序列化器。
|
||
"""
|
||
from rest_framework import serializers
|
||
|
||
from server.models import (
|
||
BossAccount, TaskLog, FilterConfig, ChatScript, ContactRecord, SystemConfig,
|
||
FollowUpConfig, FollowUpScript, FollowUpRecord
|
||
)
|
||
|
||
|
||
# ────────────────────────── 账号 ──────────────────────────
|
||
|
||
class BossAccountSerializer(serializers.ModelSerializer):
|
||
"""账号序列化器(读取用)。"""
|
||
# 运行时补充的字段(非数据库字段)
|
||
worker_name = serializers.CharField(read_only=True, default="")
|
||
worker_online = serializers.BooleanField(read_only=True, default=False)
|
||
|
||
class Meta:
|
||
model = BossAccount
|
||
fields = [
|
||
"id", "worker_id", "browser_id", "browser_name",
|
||
"boss_username", "boss_id", "is_logged_in",
|
||
"current_task_id", "current_task_status",
|
||
"checked_at", "created_at", "updated_at",
|
||
"worker_name", "worker_online",
|
||
]
|
||
|
||
|
||
class AccountBindSerializer(serializers.Serializer):
|
||
"""添加账号请求。"""
|
||
browser_name = serializers.CharField(max_length=128)
|
||
worker_id = serializers.CharField(max_length=64)
|
||
|
||
|
||
# ────────────────────────── 任务 ──────────────────────────
|
||
|
||
class TaskCreateSerializer(serializers.Serializer):
|
||
"""提交任务请求。"""
|
||
task_type = serializers.CharField(max_length=64)
|
||
id = serializers.IntegerField(required=False, allow_null=True, default=None) # 账号 ID
|
||
account_id = serializers.IntegerField(required=False, allow_null=True, default=None) # 同上,别名
|
||
boss_id = serializers.CharField(max_length=64, required=False, allow_blank=True, default="") # 即 /api/accounts 返回的 id(账号主键)
|
||
worker_id = serializers.CharField(max_length=64, required=False, allow_blank=True, default="")
|
||
account_name = serializers.CharField(max_length=128, required=False, allow_blank=True, default="")
|
||
params = serializers.JSONField(required=False, default=dict)
|
||
|
||
|
||
class TaskOutSerializer(serializers.Serializer):
|
||
"""任务信息响应。"""
|
||
task_id = serializers.CharField()
|
||
task_type = serializers.CharField()
|
||
status = serializers.CharField()
|
||
worker_id = serializers.CharField(allow_null=True)
|
||
account_name = serializers.CharField(allow_null=True)
|
||
params = serializers.DictField()
|
||
progress = serializers.CharField(allow_null=True)
|
||
result = serializers.JSONField(allow_null=True)
|
||
error = serializers.CharField(allow_null=True)
|
||
created_at = serializers.CharField()
|
||
updated_at = serializers.CharField()
|
||
|
||
|
||
# ────────────────────────── Worker ──────────────────────────
|
||
|
||
class BrowserProfileSerializer(serializers.Serializer):
|
||
"""浏览器窗口信息。"""
|
||
id = serializers.CharField()
|
||
name = serializers.CharField()
|
||
remark = serializers.CharField()
|
||
|
||
|
||
class WorkerOutSerializer(serializers.Serializer):
|
||
"""Worker 信息响应。"""
|
||
worker_id = serializers.CharField()
|
||
worker_name = serializers.CharField()
|
||
browsers = BrowserProfileSerializer(many=True)
|
||
online = serializers.BooleanField()
|
||
current_task_id = serializers.CharField(allow_null=True)
|
||
|
||
|
||
# ────────────────────────── 认证 ──────────────────────────
|
||
|
||
class LoginSerializer(serializers.Serializer):
|
||
"""登录请求。"""
|
||
username = serializers.CharField(max_length=64)
|
||
password = serializers.CharField(max_length=128)
|
||
|
||
|
||
# ────────────────────────── 筛选配置 ──────────────────────────
|
||
|
||
# 请求中可能出现的“金额”字段别名,统一映射为 min_amount / max_amount,保证请求与响应字段名一致
|
||
FILTER_AMOUNT_ALIASES = {
|
||
"minAmount": "min_amount",
|
||
"maxAmount": "max_amount",
|
||
"最小金额": "min_amount",
|
||
"最大金额": "max_amount",
|
||
}
|
||
|
||
|
||
class FilterConfigSerializer(serializers.ModelSerializer):
|
||
"""筛选配置:列表/详情返回 name, position_keywords, city, salary_min, salary_max, experience, education, is_active 等。"""
|
||
|
||
class Meta:
|
||
model = FilterConfig
|
||
fields = "__all__"
|
||
read_only_fields = ["id", "created_at", "updated_at"]
|
||
|
||
def to_representation(self, instance):
|
||
"""响应中 is_active 统一为字符串 "true" / "false"。"""
|
||
data = super().to_representation(instance)
|
||
data["is_active"] = "true" if instance.is_active else "false"
|
||
return data
|
||
|
||
def to_internal_value(self, data):
|
||
"""请求中兼容 minAmount/maxAmount、最小金额/最大金额 等别名,统一为 min_amount/max_amount。"""
|
||
if isinstance(data, dict):
|
||
data = dict(data)
|
||
for alias, canonical in FILTER_AMOUNT_ALIASES.items():
|
||
if alias in data and canonical not in data:
|
||
data[canonical] = data.pop(alias)
|
||
# 请求里 is_active 可能是字符串 "true"/"false"
|
||
if "is_active" in data and isinstance(data["is_active"], str):
|
||
data["is_active"] = data["is_active"].lower() in ("true", "1", "yes", "是")
|
||
return super().to_internal_value(data)
|
||
|
||
|
||
# ────────────────────────── 话术 ──────────────────────────
|
||
|
||
class ChatScriptSerializer(serializers.ModelSerializer):
|
||
script_type_display = serializers.CharField(source="get_script_type_display", read_only=True)
|
||
|
||
class Meta:
|
||
model = ChatScript
|
||
fields = "__all__"
|
||
read_only_fields = ["id", "created_at", "updated_at"]
|
||
|
||
|
||
# ────────────────────────── 联系记录 ──────────────────────────
|
||
|
||
class ContactRecordSerializer(serializers.ModelSerializer):
|
||
class Meta:
|
||
model = ContactRecord
|
||
fields = "__all__"
|
||
read_only_fields = ["id", "created_at"]
|
||
|
||
|
||
# ────────────────────────── 系统配置 ──────────────────────────
|
||
|
||
class SystemConfigSerializer(serializers.ModelSerializer):
|
||
class Meta:
|
||
model = SystemConfig
|
||
fields = "__all__"
|
||
read_only_fields = ["updated_at"]
|
||
|
||
# ────────────────────────── 复聊配置 ──────────────────────────
|
||
|
||
class FollowUpScriptSerializer(serializers.ModelSerializer):
|
||
"""复聊话术序列化器。"""
|
||
class Meta:
|
||
model = FollowUpScript
|
||
fields = "__all__"
|
||
read_only_fields = ["id", "created_at"]
|
||
|
||
|
||
class FollowUpConfigSerializer(serializers.ModelSerializer):
|
||
"""复聊配置序列化器(包含关联的话术列表)。"""
|
||
scripts = serializers.SerializerMethodField()
|
||
|
||
class Meta:
|
||
model = FollowUpConfig
|
||
fields = "__all__"
|
||
read_only_fields = ["id", "created_at", "updated_at"]
|
||
|
||
def get_scripts(self, obj):
|
||
"""获取该配置下的所有话术。"""
|
||
scripts = FollowUpScript.objects.filter(config_id=obj.id, is_active=True).order_by('day_number', 'order')
|
||
return FollowUpScriptSerializer(scripts, many=True).data
|
||
|
||
|
||
class FollowUpRecordSerializer(serializers.ModelSerializer):
|
||
"""复聊记录序列化器。"""
|
||
class Meta:
|
||
model = FollowUpRecord
|
||
fields = "__all__"
|
||
read_only_fields = ["id", "sent_at"]
|