# ============================================================================= # 企微IT智能服务台 — 排查模板 API # ============================================================================= # 说明:提供排查模板的 CRUD 接口 # 接口列表: # GET /api/troubleshooting-templates — 获取排查模板列表 # GET /api/troubleshooting-templates/{id} — 获取排查模板详情 # POST /api/troubleshooting-templates — 新增模板(管理员) # PUT /api/troubleshooting-templates/{id} — 修改模板(管理员) # DELETE /api/troubleshooting-templates/{id} — 删除模板(管理员) # Mock: 预置 8 套常见问题模板(VPN/邮箱/系统/账号等) # ============================================================================= from datetime import datetime from typing import Any, Dict, List, Optional from fastapi import APIRouter, HTTPException from pydantic import BaseModel, Field from app.utils.response import success_response, AppException # 创建路由器 router = APIRouter(prefix="/troubleshooting-templates", tags=["排查模板"]) # -------------------------------------------------------------------------- # 请求/响应 Schema # -------------------------------------------------------------------------- class PathStepSchema(BaseModel): """排障步骤路径节点 Schema。""" label: str = Field(..., description="步骤标题") status: str = Field(default="pending", description="步骤状态: done/current/pending") class FlowchartNodeSchema(BaseModel): """决策树递归节点 Schema。""" id: str = Field(..., description="节点唯一标识") type: str = Field(..., description="节点类型: step/decision") label: str = Field(..., description="节点标签") status: Optional[str] = Field(None, description="节点状态: done/current/pending") children: Optional[List["FlowchartNodeSchema"]] = Field(None, description="子节点列表") yes_branch: Optional["FlowchartNodeSchema"] = Field(None, description="'是' 分支") no_branch: Optional["FlowchartNodeSchema"] = Field(None, description="'否' 分支") class TroubleshootingTemplateCreateRequest(BaseModel): """创建排查模板请求 Schema。""" name: str = Field(..., min_length=1, max_length=256, description="模板名称") category: str = Field(default="system", description="分类: vpn/email/system/account") path_steps: List[Dict[str, Any]] = Field(default_factory=list, description="排障步骤路径") flowchart: Dict[str, Any] = Field(default_factory=dict, description="流程图定义") is_active: bool = Field(default=True, description="是否启用") class TroubleshootingTemplateUpdateRequest(BaseModel): """更新排查模板请求 Schema。""" name: Optional[str] = Field(None, max_length=256, description="模板名称") category: Optional[str] = Field(None, description="分类") path_steps: Optional[List[Dict[str, Any]]] = Field(None, description="排障步骤路径") flowchart: Optional[Dict[str, Any]] = Field(None, description="流程图定义") is_active: Optional[bool] = Field(None, description="是否启用") class TroubleshootingTemplateResponse(BaseModel): """排查模板响应 Schema。""" id: str name: str category: str path_steps: List[Dict[str, Any]] flowchart: Dict[str, Any] is_active: bool created_at: str updated_at: str class TroubleshootingTemplateListResponse(BaseModel): """排查模板列表响应 Schema。""" items: List[TroubleshootingTemplateResponse] total: int # -------------------------------------------------------------------------- # Mock 数据 — 预置 8 套常见问题模板 # -------------------------------------------------------------------------- def _build_vpn_flowchart() -> Dict[str, Any]: """构建 VPN 故障排查流程图。""" return { "id": "fc-vpn-1", "type": "step", "label": "确认VPN客户端版本", "status": "done", "children": [ { "id": "fc-vpn-2", "type": "decision", "label": "版本是否为最新?", "status": "pending", "yes_branch": { "id": "fc-vpn-3", "type": "step", "label": "清除DNS缓存并重连", "status": "current", "children": [ { "id": "fc-vpn-4", "type": "decision", "label": "重连是否成功?", "status": "pending", "yes_branch": { "id": "fc-vpn-5", "type": "step", "label": "回访确认", "status": "pending", }, "no_branch": { "id": "fc-vpn-6", "type": "step", "label": "发起远程协助", "status": "pending", "children": [ { "id": "fc-vpn-7", "type": "decision", "label": "远程能否解决?", "status": "pending", "yes_branch": { "id": "fc-vpn-8", "type": "step", "label": "回访确认并结单", "status": "pending", }, "no_branch": { "id": "fc-vpn-9", "type": "step", "label": "升级至二线团队", "status": "pending", }, }, ], }, }, ], }, "no_branch": { "id": "fc-vpn-10", "type": "step", "label": "升级VPN客户端到最新版", "status": "pending", "children": [ { "id": "fc-vpn-11", "type": "step", "label": "重试连接", "status": "pending", }, ], }, }, ], } def _build_email_flowchart() -> Dict[str, Any]: """构建邮箱故障排查流程图。""" return { "id": "fc-email-1", "type": "step", "label": "确认邮箱账号状态", "status": "done", "children": [ { "id": "fc-email-2", "type": "decision", "label": "账号是否被锁定?", "status": "pending", "yes_branch": { "id": "fc-email-3", "type": "step", "label": "解锁账号并重置密码", "status": "current", }, "no_branch": { "id": "fc-email-4", "type": "step", "label": "检查Outlook配置", "status": "pending", "children": [ { "id": "fc-email-5", "type": "decision", "label": "配置是否正确?", "status": "pending", "yes_branch": { "id": "fc-email-6", "type": "step", "label": "清理Outlook缓存", "status": "pending", }, "no_branch": { "id": "fc-email-7", "type": "step", "label": "重新配置Outlook", "status": "pending", }, }, ], }, }, ], } def _build_system_flowchart() -> Dict[str, Any]: """构建系统登录异常排查流程图。""" return { "id": "fc-sys-1", "type": "step", "label": "确认系统服务是否正常", "status": "current", "children": [ { "id": "fc-sys-2", "type": "decision", "label": "系统服务是否正常?", "status": "pending", "yes_branch": { "id": "fc-sys-3", "type": "step", "label": "清除浏览器缓存", "status": "pending", "children": [ { "id": "fc-sys-4", "type": "decision", "label": "清除后是否恢复?", "status": "pending", "yes_branch": { "id": "fc-sys-5", "type": "step", "label": "回访确认并结单", "status": "pending", }, "no_branch": { "id": "fc-sys-6", "type": "step", "label": "更换浏览器重试", "status": "pending", }, }, ], }, "no_branch": { "id": "fc-sys-7", "type": "step", "label": "联系运维检查服务端", "status": "pending", }, }, ], } def _build_account_flowchart() -> Dict[str, Any]: """构建账号权限问题排查流程图。""" return { "id": "fc-acc-1", "type": "step", "label": "确认权限需求与合规性", "status": "current", "children": [ { "id": "fc-acc-2", "type": "decision", "label": "权限是否符合策略?", "status": "pending", "yes_branch": { "id": "fc-acc-3", "type": "step", "label": "提交权限审批流程", "status": "pending", "children": [ { "id": "fc-acc-4", "type": "step", "label": "审批通过后配置权限", "status": "pending", }, ], }, "no_branch": { "id": "fc-acc-5", "type": "step", "label": "建议替代方案或申请特批", "status": "pending", }, }, ], } def _build_network_flowchart() -> Dict[str, Any]: """构建网络连接问题排查流程图。""" return { "id": "fc-net-1", "type": "step", "label": "确认网络连接状态", "status": "current", "children": [ { "id": "fc-net-2", "type": "decision", "label": "能否ping通网关?", "status": "pending", "yes_branch": { "id": "fc-net-3", "type": "step", "label": "检查DNS解析", "status": "pending", "children": [ { "id": "fc-net-4", "type": "decision", "label": "DNS是否正常?", "status": "pending", "yes_branch": { "id": "fc-net-5", "type": "step", "label": "检查防火墙规则", "status": "pending", }, "no_branch": { "id": "fc-net-6", "type": "step", "label": "手动配置DNS服务器", "status": "pending", }, }, ], }, "no_branch": { "id": "fc-net-7", "type": "step", "label": "检查网线和交换机端口", "status": "pending", }, }, ], } def _build_printer_flowchart() -> Dict[str, Any]: """构建打印机故障排查流程图。""" return { "id": "fc-prt-1", "type": "step", "label": "确认打印机连接状态", "status": "current", "children": [ { "id": "fc-prt-2", "type": "decision", "label": "打印机是否在线?", "status": "pending", "yes_branch": { "id": "fc-prt-3", "type": "step", "label": "清除打印队列并重启打印服务", "status": "pending", "children": [ { "id": "fc-prt-4", "type": "decision", "label": "打印是否恢复?", "status": "pending", "yes_branch": { "id": "fc-prt-5", "type": "step", "label": "回访确认", "status": "pending", }, "no_branch": { "id": "fc-prt-6", "type": "step", "label": "重新安装打印机驱动", "status": "pending", }, }, ], }, "no_branch": { "id": "fc-prt-7", "type": "step", "label": "检查网络连接和打印机电源", "status": "pending", }, }, ], } def _build_office_flowchart() -> Dict[str, Any]: """构建 Office 软件问题排查流程图。""" return { "id": "fc-off-1", "type": "step", "label": "确认Office版本和激活状态", "status": "current", "children": [ { "id": "fc-off-2", "type": "decision", "label": "Office是否正常激活?", "status": "pending", "yes_branch": { "id": "fc-off-3", "type": "step", "label": "修复Office安装", "status": "pending", "children": [ { "id": "fc-off-4", "type": "decision", "label": "修复后是否正常?", "status": "pending", "yes_branch": { "id": "fc-off-5", "type": "step", "label": "回访确认", "status": "pending", }, "no_branch": { "id": "fc-off-6", "type": "step", "label": "卸载重装Office", "status": "pending", }, }, ], }, "no_branch": { "id": "fc-off-7", "type": "step", "label": "重新激活Office许可证", "status": "pending", }, }, ], } def _build_password_flowchart() -> Dict[str, Any]: """构建密码重置问题排查流程图。""" return { "id": "fc-pwd-1", "type": "step", "label": "确认账号状态和锁定原因", "status": "current", "children": [ { "id": "fc-pwd-2", "type": "decision", "label": "账号是否被锁定?", "status": "pending", "yes_branch": { "id": "fc-pwd-3", "type": "step", "label": "解锁账号并引导自助重置", "status": "pending", "children": [ { "id": "fc-pwd-4", "type": "decision", "label": "自助重置是否成功?", "status": "pending", "yes_branch": { "id": "fc-pwd-5", "type": "step", "label": "回访确认", "status": "pending", }, "no_branch": { "id": "fc-pwd-6", "type": "step", "label": "管理员手动重置密码", "status": "pending", }, }, ], }, "no_branch": { "id": "fc-pwd-7", "type": "step", "label": "检查SSO单点登录配置", "status": "pending", }, }, ], } # 所有 Mock 模板数据 MOCK_TEMPLATES: List[dict] = [ { "id": "tpl-vpn-001", "name": "VPN连接故障", "category": "vpn", "path_steps": [ {"label": "确认VPN版本", "status": "done"}, {"label": "清除缓存重连", "status": "current"}, {"label": "远程排查", "status": "pending"}, {"label": "升级客户端", "status": "pending"}, {"label": "回访确认", "status": "pending"}, ], "flowchart": _build_vpn_flowchart(), "is_active": True, "created_at": "2025-06-01T08:00:00Z", "updated_at": "2025-06-15T10:30:00Z", }, { "id": "tpl-email-001", "name": "邮箱登录故障", "category": "email", "path_steps": [ {"label": "确认邮箱状态", "status": "done"}, {"label": "重置密码", "status": "current"}, {"label": "检查配置", "status": "pending"}, {"label": "清理缓存", "status": "pending"}, {"label": "回访确认", "status": "pending"}, ], "flowchart": _build_email_flowchart(), "is_active": True, "created_at": "2025-06-01T08:00:00Z", "updated_at": "2025-06-20T14:00:00Z", }, { "id": "tpl-system-001", "name": "系统登录异常", "category": "system", "path_steps": [ {"label": "确认系统状态", "status": "current"}, {"label": "清除浏览器缓存", "status": "pending"}, {"label": "更换浏览器", "status": "pending"}, {"label": "检查网络权限", "status": "pending"}, {"label": "回访确认", "status": "pending"}, ], "flowchart": _build_system_flowchart(), "is_active": True, "created_at": "2025-06-01T08:00:00Z", "updated_at": "2025-06-25T09:15:00Z", }, { "id": "tpl-account-001", "name": "账号权限问题", "category": "account", "path_steps": [ {"label": "确认权限需求", "status": "current"}, {"label": "提交审批", "status": "pending"}, {"label": "配置权限", "status": "pending"}, {"label": "验证权限", "status": "pending"}, {"label": "回访确认", "status": "pending"}, ], "flowchart": _build_account_flowchart(), "is_active": True, "created_at": "2025-06-01T08:00:00Z", "updated_at": "2025-06-28T16:45:00Z", }, { "id": "tpl-network-001", "name": "网络连接问题", "category": "system", "path_steps": [ {"label": "确认网络状态", "status": "current"}, {"label": "检查DNS配置", "status": "pending"}, {"label": "检查防火墙", "status": "pending"}, {"label": "更换网口/网线", "status": "pending"}, {"label": "回访确认", "status": "pending"}, ], "flowchart": _build_network_flowchart(), "is_active": True, "created_at": "2025-06-05T10:00:00Z", "updated_at": "2025-06-22T11:30:00Z", }, { "id": "tpl-printer-001", "name": "打印机故障", "category": "system", "path_steps": [ {"label": "确认打印机状态", "status": "current"}, {"label": "清除打印队列", "status": "pending"}, {"label": "重新安装驱动", "status": "pending"}, {"label": "检查网络连接", "status": "pending"}, {"label": "回访确认", "status": "pending"}, ], "flowchart": _build_printer_flowchart(), "is_active": True, "created_at": "2025-06-10T09:00:00Z", "updated_at": "2025-07-01T08:00:00Z", }, { "id": "tpl-office-001", "name": "Office软件问题", "category": "system", "path_steps": [ {"label": "确认Office版本", "status": "current"}, {"label": "修复安装", "status": "pending"}, {"label": "重新激活", "status": "pending"}, {"label": "卸载重装", "status": "pending"}, {"label": "回访确认", "status": "pending"}, ], "flowchart": _build_office_flowchart(), "is_active": True, "created_at": "2025-06-12T14:00:00Z", "updated_at": "2025-06-30T10:00:00Z", }, { "id": "tpl-password-001", "name": "密码重置问题", "category": "account", "path_steps": [ {"label": "确认账号状态", "status": "current"}, {"label": "解锁账号", "status": "pending"}, {"label": "引导自助重置", "status": "pending"}, {"label": "管理员重置", "status": "pending"}, {"label": "回访确认", "status": "pending"}, ], "flowchart": _build_password_flowchart(), "is_active": True, "created_at": "2025-06-15T08:00:00Z", "updated_at": "2025-07-01T09:00:00Z", }, ] # -------------------------------------------------------------------------- # API 接口 # -------------------------------------------------------------------------- @router.get("") async def list_troubleshooting_templates( category: Optional[str] = None, ): """获取排查模板列表。 支持按分类过滤。 """ items = MOCK_TEMPLATES # 按分类过滤 if category: items = [item for item in items if item["category"] == category] # 只返回启用的模板 items = [item for item in items if item.get("is_active", True)] return success_response(data={ "items": [TroubleshootingTemplateResponse(**item).model_dump() for item in items], "total": len(items), }) @router.get("/{template_id}") async def get_troubleshooting_template(template_id: str): """获取排查模板详情。""" for item in MOCK_TEMPLATES: if item["id"] == template_id: return success_response(data=TroubleshootingTemplateResponse(**item).model_dump()) raise AppException(code=1003, message=f"排查模板 {template_id} 不存在") @router.post("") async def create_troubleshooting_template(request: TroubleshootingTemplateCreateRequest): """新增排查模板(管理员)。""" new_template = { "id": f"tpl-{datetime.now().strftime('%Y%m%d%H%M%S')}", "name": request.name, "category": request.category, "path_steps": request.path_steps, "flowchart": request.flowchart, "is_active": request.is_active, "created_at": datetime.now().isoformat(), "updated_at": datetime.now().isoformat(), } MOCK_TEMPLATES.append(new_template) return success_response(data=TroubleshootingTemplateResponse(**new_template).model_dump()) @router.put("/{template_id}") async def update_troubleshooting_template( template_id: str, request: TroubleshootingTemplateUpdateRequest, ): """修改排查模板(管理员)。""" for item in MOCK_TEMPLATES: if item["id"] == template_id: if request.name is not None: item["name"] = request.name if request.category is not None: item["category"] = request.category if request.path_steps is not None: item["path_steps"] = request.path_steps if request.flowchart is not None: item["flowchart"] = request.flowchart if request.is_active is not None: item["is_active"] = request.is_active item["updated_at"] = datetime.now().isoformat() return success_response(data=TroubleshootingTemplateResponse(**item).model_dump()) raise AppException(code=1003, message=f"排查模板 {template_id} 不存在") @router.delete("/{template_id}") async def delete_troubleshooting_template(template_id: str): """删除排查模板(管理员)。""" for i, item in enumerate(MOCK_TEMPLATES): if item["id"] == template_id: MOCK_TEMPLATES.pop(i) return success_response(data=None, message=f"排查模板 {template_id} 已删除") raise AppException(code=1003, message=f"排查模板 {template_id} 不存在")