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