Files
boss_dp/server/api/followup.py
2026-03-05 10:27:28 +08:00

188 lines
6.5 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# -*- coding: utf-8 -*-
"""
复聊配置 API需要登录
- GET /api/followup-configs -> 查询复聊配置列表
- POST /api/followup-configs -> 创建复聊配置
- GET /api/followup-configs/{id} -> 查询单个配置
- PUT /api/followup-configs/{id} -> 更新配置
- DELETE /api/followup-configs/{id} -> 删除配置
- GET /api/followup-scripts -> 查询话术列表
- POST /api/followup-scripts -> 创建话术
- GET /api/followup-scripts/{id} -> 查询单个话术
- PUT /api/followup-scripts/{id} -> 更新话术
- DELETE /api/followup-scripts/{id} -> 删除话术
- GET /api/followup-records -> 查询复聊记录
- POST /api/followup-records/send -> 手动发送复聊消息
"""
from rest_framework import status
from rest_framework.decorators import api_view
from server.core.response import api_success, api_error
from server.models import FollowUpConfig, FollowUpScript, FollowUpRecord, ContactRecord
from server.serializers import (
FollowUpConfigSerializer,
FollowUpScriptSerializer,
FollowUpRecordSerializer
)
# ────────────────────────── 复聊配置 ──────────────────────────
@api_view(["GET", "POST"])
def followup_config_list(request):
"""复聊配置列表。"""
if request.method == "GET":
position = request.query_params.get("position")
is_active = request.query_params.get("is_active")
qs = FollowUpConfig.objects.all()
if position:
qs = qs.filter(position__icontains=position)
if is_active is not None:
qs = qs.filter(is_active=is_active.lower() in ("true", "1"))
configs = qs.order_by("-created_at")
return api_success(FollowUpConfigSerializer(configs, many=True).data)
# POST
ser = FollowUpConfigSerializer(data=request.data)
ser.is_valid(raise_exception=True)
ser.save()
return api_success(ser.data, http_status=status.HTTP_201_CREATED)
@api_view(["GET", "PUT", "DELETE"])
def followup_config_detail(request, pk):
"""复聊配置详情。"""
try:
obj = FollowUpConfig.objects.get(pk=pk)
except FollowUpConfig.DoesNotExist:
return api_error(status.HTTP_404_NOT_FOUND, "复聊配置不存在")
if request.method == "GET":
return api_success(FollowUpConfigSerializer(obj).data)
if request.method == "PUT":
ser = FollowUpConfigSerializer(obj, data=request.data, partial=True)
ser.is_valid(raise_exception=True)
ser.save()
return api_success(ser.data)
# DELETE
obj.delete()
return api_success(msg="复聊配置已删除")
# ────────────────────────── 复聊话术 ──────────────────────────
@api_view(["GET", "POST"])
def followup_script_list(request):
"""复聊话术列表。"""
if request.method == "GET":
config_id = request.query_params.get("config_id")
day_number = request.query_params.get("day_number")
qs = FollowUpScript.objects.all()
if config_id:
qs = qs.filter(config_id=config_id)
if day_number is not None:
qs = qs.filter(day_number=day_number)
scripts = qs.order_by("config_id", "day_number", "order")
return api_success(FollowUpScriptSerializer(scripts, many=True).data)
# POST
ser = FollowUpScriptSerializer(data=request.data)
ser.is_valid(raise_exception=True)
ser.save()
return api_success(ser.data, http_status=status.HTTP_201_CREATED)
@api_view(["GET", "PUT", "DELETE"])
def followup_script_detail(request, pk):
"""复聊话术详情。"""
try:
obj = FollowUpScript.objects.get(pk=pk)
except FollowUpScript.DoesNotExist:
return api_error(status.HTTP_404_NOT_FOUND, "复聊话术不存在")
if request.method == "GET":
return api_success(FollowUpScriptSerializer(obj).data)
if request.method == "PUT":
ser = FollowUpScriptSerializer(obj, data=request.data, partial=True)
ser.is_valid(raise_exception=True)
ser.save()
return api_success(ser.data)
# DELETE
obj.delete()
return api_success(msg="复聊话术已删除")
# ────────────────────────── 复聊记录 ──────────────────────────
@api_view(["GET"])
def followup_record_list(request):
"""复聊记录列表。"""
contact_id = request.query_params.get("contact_id")
config_id = request.query_params.get("config_id")
got_reply = request.query_params.get("got_reply")
page = int(request.query_params.get("page", 1))
page_size = int(request.query_params.get("page_size", 20))
qs = FollowUpRecord.objects.all()
if contact_id:
qs = qs.filter(contact_id=contact_id)
if config_id:
qs = qs.filter(config_id=config_id)
if got_reply is not None:
qs = qs.filter(got_reply=got_reply.lower() in ("true", "1"))
total = qs.count()
start = (page - 1) * page_size
end = start + page_size
records = qs[start:end]
return api_success({
"total": total,
"page": page,
"page_size": page_size,
"results": FollowUpRecordSerializer(records, many=True).data,
})
@api_view(["POST"])
def followup_send_manual(request):
"""手动发送复聊消息。"""
contact_id = request.data.get("contact_id")
content = request.data.get("content", "").strip()
if not contact_id:
return api_error(status.HTTP_400_BAD_REQUEST, "请提供 contact_id")
if not content:
return api_error(status.HTTP_400_BAD_REQUEST, "请提供发送内容")
try:
contact = ContactRecord.objects.get(pk=contact_id)
except ContactRecord.DoesNotExist:
return api_error(status.HTTP_404_NOT_FOUND, "联系人不存在")
# TODO: 这里需要调用浏览器自动化发送消息
# 暂时只记录到数据库
record = FollowUpRecord.objects.create(
contact_id=contact_id,
config_id=0, # 手动发送
script_id=0, # 手动发送
day_number=0,
content=content,
)
return api_success({
"record": FollowUpRecordSerializer(record).data,
"message": "复聊消息已发送"
})