# ============================================================================= # 企微IT智能服务台 — 会议室报修业务服务 # ============================================================================= # 说明:处理终端报修的完整流程: # 1. 创建报修记录到 meetingroom_repair 表 # 2. 创建IT工单会话(Conversation),状态为 queued(排队等待坐席) # 3. 创建初始消息(故障描述),sender_type=system # 4. 通过企微消息通知IT管理员 # 5. 通过WS推送报修通知到坐席端 # # 设计决策: # - 报修自动创建工单会话,复用现有IT服务台流程 # - 报修人未登录时使用"匿名"身份,但仍创建工单 # - 通知管理员和坐席同步进行,不影响主流程 # ============================================================================= import logging import uuid from datetime import datetime from typing import Optional from sqlalchemy.ext.asyncio import AsyncSession from app.config import settings from app.models.conversation import Conversation from app.models.message import Message from app.models.meetingroom_repair import MeetingroomRepair from app.services.wecom_service import WecomService logger = logging.getLogger(__name__) # 设备类型中文映射 DEVICE_TYPE_LABELS = { "projector": "投影仪", "video_conf": "视频会议设备", "aircon": "空调", "desk_chair": "桌椅", "network": "网络", "other": "其他设备", } class RepairService: """会议室报修业务服务。 处理终端报修的完整流程:记录 + 创建工单 + 通知。 """ def __init__( self, db: AsyncSession, wecom_service: Optional[WecomService] = None, ) -> None: """初始化报修服务。 Args: db: 数据库会话 wecom_service: 企微服务实例(用于发送通知消息) """ self.db = db self.wecom = wecom_service async def submit_repair( self, terminal_sn: str, meetingroom_id: int, meetingroom_name: str, device_type: str, fault_description: str, reporter_name: Optional[str] = None, reporter_userid: Optional[str] = None, ) -> dict: """提交报修,创建工单会话并通知。 Args: terminal_sn: 终端序列号 meetingroom_id: 企微会议室ID meetingroom_name: 会议室名称 device_type: 故障设备类型 fault_description: 故障描述 reporter_name: 报修人姓名(为空则"匿名") reporter_userid: 报修人企微userid(为空则空字符串) Returns: dict: {"repair_id": int, "conversation_id": str} """ # 报修人信息处理 name = reporter_name or "匿名(终端报修)" userid = reporter_userid or "" # 设备类型中文名 device_label = DEVICE_TYPE_LABELS.get(device_type, device_type) # 构造工单主题 subject = f"会议室报修:{meetingroom_name} - {device_label}" # 1. 创建IT工单会话 conversation_id = str(uuid.uuid4()) conversation = Conversation( id=conversation_id, corp_id=settings.wecom_corp_id, employee_id=userid or f"terminal:{terminal_sn}", employee_name=name, department="", position="", level="", status="queued", urgency_score=3, # 报修默认中等紧急 tags={"source": "terminal_repair", "terminal_sn": terminal_sn, "meetingroom_id": meetingroom_id}, last_message_at=datetime.now(), last_message_summary=fault_description[:256], ) self.db.add(conversation) # 2. 创建初始系统消息(故障描述) message = Message( conversation_id=conversation_id, sender_type="system", sender_id="system", sender_name="系统", content=f"【终端报修】\n会议室: {meetingroom_name}\n设备类型: {device_label}\n故障描述: {fault_description}\n报修人: {name}\n终端SN: {terminal_sn}", msg_type="text", status="sent", ) self.db.add(message) # 3. 创建报修记录 repair = MeetingroomRepair( terminal_sn=terminal_sn, meetingroom_id=meetingroom_id, meetingroom_name=meetingroom_name, device_type=device_type, fault_description=fault_description, reporter_name=name, reporter_userid=userid, conversation_id=conversation_id, status=0, ) self.db.add(repair) # 提交事务 await self.db.commit() await self.db.refresh(repair) # 4. 异步通知IT管理员(不阻塞主流程) try: await self._notify_admins(subject, fault_description, meetingroom_name, name) except Exception as e: logger.warning(f"报修通知管理员失败(不影响主流程): {e}") # 5. 通过WS推送报修通知到坐席端 try: await self._notify_agents(subject, conversation_id, meetingroom_name) except Exception as e: logger.warning(f"报修WS通知坐席失败(不影响主流程): {e}") logger.info( f"报修创建成功: repair_id={repair.id}, conversation_id={conversation_id}, " f"room={meetingroom_name}, device={device_type}" ) return { "repair_id": repair.id, "conversation_id": conversation_id, } async def _notify_admins( self, subject: str, description: str, room_name: str, reporter: str, ) -> None: """通过企微消息通知IT管理员。""" if not self.wecom: return # 通知内容 content = ( f"【会议室报修通知】\n" f"会议室: {room_name}\n" f"报修人: {reporter}\n" f"问题: {description}\n" f"时间: {datetime.now().strftime('%Y-%m-%d %H:%M')}\n" f"请及时处理。" ) # 从配置获取管理员userid列表 admin_userids = [] if settings.wecom_agent_userids: admin_userids = [uid.strip() for uid in settings.wecom_agent_userids.split(",") if uid.strip()] if admin_userids: for uid in admin_userids: try: await self.wecom.send_text_message(uid, content) except Exception as e: logger.warning(f"发送报修通知给 {uid} 失败: {e}") async def _notify_agents( self, subject: str, conversation_id: str, room_name: str, ) -> None: """通过WS推送报修通知到坐席端。""" from app.services.ws_manager import manager # 构造推送消息 message_data = { "type": "new_conversation", "conversation_id": conversation_id, "source": "terminal_repair", "subject": subject, "room_name": room_name, "timestamp": datetime.now().isoformat(), } # 广播到所有在线坐席 await manager.broadcast(message_data)