Files

216 lines
6.4 KiB
Python
Raw Permalink 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.
# =============================================================================
# 企微IT智能服务台 — 坐席备注 API
# =============================================================================
# 说明:坐席端的备注管理接口,包括:
# 1. GET /api/agent-notes/{employee_id} — 获取员工的所有备注
# 2. POST /api/agent-notes — 添加备注
# 3. PUT /api/agent-notes/{id} — 更新备注
# 4. DELETE /api/agent-notes/{id} — 删除备注
# =============================================================================
import logging
from datetime import datetime
from typing import List, Optional
from uuid import UUID
from fastapi import APIRouter, Depends, Query
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession
from app.database import get_db
from app.models.agent_note import AgentNote
from app.models.conversation import Conversation
from app.utils.response import AppException, ERR_NOT_FOUND, success_response
logger = logging.getLogger(__name__)
# 创建路由器
router = APIRouter()
# --------------------------------------------------------------------------
# GET /api/agent-notes/{employee_id} — 获取员工的所有备注
# --------------------------------------------------------------------------
@router.get("/agent-notes/{employee_id}")
async def list_agent_notes(
employee_id: str,
db: AsyncSession = Depends(get_db),
):
"""获取员工的所有备注。
通过员工ID查找其所有会话的备注。
用于坐席端用户信息面板展示。
Args:
employee_id: 员工企微 UserID
db: 数据库会话
Returns:
Dict: 统一响应格式,包含备注列表
"""
# 查找该员工所有会话的备注
stmt = (
select(AgentNote)
.join(Conversation, AgentNote.conversation_id == Conversation.id)
.where(Conversation.employee_id == employee_id)
.order_by(AgentNote.created_at.desc())
)
result = await db.execute(stmt)
notes = list(result.scalars().all())
items = [
{
"id": str(note.id),
"conversation_id": str(note.conversation_id),
"agent_id": note.agent_id,
"content": note.content,
"created_at": note.created_at.isoformat() if note.created_at else "",
"updated_at": note.updated_at.isoformat() if note.updated_at else "",
}
for note in notes
]
return success_response(data={"items": items})
# --------------------------------------------------------------------------
# POST /api/agent-notes — 添加备注
# --------------------------------------------------------------------------
@router.post("/agent-notes")
async def create_agent_note(
body: dict,
db: AsyncSession = Depends(get_db),
):
"""添加坐席备注。
Args:
body: 备注请求体(包含 conversation_id, agent_id, content
db: 数据库会话
Returns:
Dict: 统一响应格式,包含创建的备注
"""
conversation_id = body.get("conversation_id", "")
agent_id = body.get("agent_id", "")
content = body.get("content", "")
if not conversation_id or not agent_id or not content:
raise AppException(1001, "缺少必要参数: conversation_id, agent_id, content")
# 校验会话存在
try:
conv_uuid = UUID(conversation_id)
except ValueError:
raise AppException(1001, "无效的 conversation_id 格式")
conv_stmt = select(Conversation).where(Conversation.id == conv_uuid)
conv_result = await db.execute(conv_stmt)
if not conv_result.scalars().first():
raise ERR_NOT_FOUND
# 创建备注
note = AgentNote(
conversation_id=conv_uuid,
agent_id=agent_id,
content=content,
)
db.add(note)
await db.flush()
logger.info(f"添加坐席备注: conv_id={conversation_id}, agent={agent_id}")
note_data = {
"id": str(note.id),
"conversation_id": str(note.conversation_id),
"agent_id": note.agent_id,
"content": note.content,
"created_at": note.created_at.isoformat() if note.created_at else "",
"updated_at": note.updated_at.isoformat() if note.updated_at else "",
}
return success_response(data=note_data)
# --------------------------------------------------------------------------
# PUT /api/agent-notes/{id} — 更新备注
# --------------------------------------------------------------------------
@router.put("/agent-notes/{note_id}")
async def update_agent_note(
note_id: UUID,
body: dict,
db: AsyncSession = Depends(get_db),
):
"""更新坐席备注。
Args:
note_id: 备注ID
body: 更新请求体(包含 content
db: 数据库会话
Returns:
Dict: 统一响应格式,包含更新后的备注
"""
# 查找备注
stmt = select(AgentNote).where(AgentNote.id == note_id)
result = await db.execute(stmt)
note = result.scalars().first()
if not note:
raise ERR_NOT_FOUND
# 更新内容
content = body.get("content")
if content is not None:
note.content = content
note.updated_at = datetime.now()
db.add(note)
await db.flush()
logger.info(f"更新坐席备注: id={note_id}")
note_data = {
"id": str(note.id),
"conversation_id": str(note.conversation_id),
"agent_id": note.agent_id,
"content": note.content,
"created_at": note.created_at.isoformat() if note.created_at else "",
"updated_at": note.updated_at.isoformat() if note.updated_at else "",
}
return success_response(data=note_data)
# --------------------------------------------------------------------------
# DELETE /api/agent-notes/{id} — 删除备注
# --------------------------------------------------------------------------
@router.delete("/agent-notes/{note_id}")
async def delete_agent_note(
note_id: UUID,
db: AsyncSession = Depends(get_db),
):
"""删除坐席备注。
Args:
note_id: 备注ID
db: 数据库会话
Returns:
Dict: 统一响应格式
"""
# 查找备注
stmt = select(AgentNote).where(AgentNote.id == note_id)
result = await db.execute(stmt)
note = result.scalars().first()
if not note:
raise ERR_NOT_FOUND
# 物理删除
await db.delete(note)
await db.flush()
logger.info(f"删除坐席备注: id={note_id}")
return success_response(data=None, message="删除成功")