Files
wecom_it_smart_desk/backend/app/api/troubleshooting_templates.py
T

720 lines
27 KiB
Python
Raw Normal View History

# =============================================================================
# 企微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} 不存在")