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="删除成功")
|