216 lines
6.4 KiB
Python
216 lines
6.4 KiB
Python
# =============================================================================
|
||
# 企微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="删除成功")
|