440 lines
14 KiB
Python
440 lines
14 KiB
Python
|
|
# =============================================================================
|
|||
|
|
# 企微IT智能服务台 — 待办事项 API
|
|||
|
|
# =============================================================================
|
|||
|
|
# 说明:提供待办事项的 CRUD 接口
|
|||
|
|
# 接口列表:
|
|||
|
|
# GET /api/todo-items — 获取当前坐席待办列表
|
|||
|
|
# GET /api/todo-items/{id} — 获取待办详情
|
|||
|
|
# PUT /api/todo-items/{id}/status — 更新待办状态
|
|||
|
|
# Mock: 预置示例待办数据,不连接真实外部系统
|
|||
|
|
# =============================================================================
|
|||
|
|
|
|||
|
|
from datetime import datetime
|
|||
|
|
from typing import List, Optional
|
|||
|
|
|
|||
|
|
from fastapi import APIRouter, HTTPException
|
|||
|
|
from pydantic import BaseModel, Field
|
|||
|
|
|
|||
|
|
from app.utils.response import success_response, AppException
|
|||
|
|
|
|||
|
|
# 创建路由器
|
|||
|
|
router = APIRouter(prefix="/todo-items", tags=["待办事项"])
|
|||
|
|
|
|||
|
|
|
|||
|
|
# --------------------------------------------------------------------------
|
|||
|
|
# 请求/响应 Schema
|
|||
|
|
# --------------------------------------------------------------------------
|
|||
|
|
|
|||
|
|
class TodoStatusUpdateRequest(BaseModel):
|
|||
|
|
"""更新待办状态请求 Schema。"""
|
|||
|
|
status: str = Field(..., description="新状态: pending/processing/resolved")
|
|||
|
|
|
|||
|
|
|
|||
|
|
class TodoItemResponse(BaseModel):
|
|||
|
|
"""待办事项响应 Schema。"""
|
|||
|
|
id: str
|
|||
|
|
type: str
|
|||
|
|
title: str
|
|||
|
|
priority: str
|
|||
|
|
description: dict
|
|||
|
|
status: str
|
|||
|
|
assigned_agent_id: Optional[str] = None
|
|||
|
|
corp_id: str = ""
|
|||
|
|
created_at: str
|
|||
|
|
updated_at: str
|
|||
|
|
|
|||
|
|
|
|||
|
|
class TodoItemListResponse(BaseModel):
|
|||
|
|
"""待办事项列表响应 Schema。"""
|
|||
|
|
items: List[TodoItemResponse]
|
|||
|
|
total: int
|
|||
|
|
|
|||
|
|
|
|||
|
|
# --------------------------------------------------------------------------
|
|||
|
|
# Mock 数据 — 预置示例待办(共 20 条,覆盖全部类型 × 状态)
|
|||
|
|
# --------------------------------------------------------------------------
|
|||
|
|
MOCK_TODO_ITEMS: List[dict] = [
|
|||
|
|
# ========== 工单(ticket)==========
|
|||
|
|
# 待处理
|
|||
|
|
{
|
|||
|
|
"id": "todo-001",
|
|||
|
|
"type": "ticket",
|
|||
|
|
"title": "VPN连接失败 — 财务部张伟",
|
|||
|
|
"priority": "urgent",
|
|||
|
|
"description": {
|
|||
|
|
"employee_name": "张伟",
|
|||
|
|
"department": "财务部",
|
|||
|
|
"error": "VPN Error 691",
|
|||
|
|
"steps": ["检查账号状态", "重置密码", "检查VPN配置"],
|
|||
|
|
},
|
|||
|
|
"status": "pending",
|
|||
|
|
"assigned_agent_id": "agent-001",
|
|||
|
|
"corp_id": "ww1234567890",
|
|||
|
|
"created_at": "2026-06-05T09:15:00Z",
|
|||
|
|
"updated_at": "2026-06-05T09:15:00Z",
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"id": "todo-007",
|
|||
|
|
"type": "ticket",
|
|||
|
|
"title": "OA系统登录异常 — 人事部刘芳",
|
|||
|
|
"priority": "urgent",
|
|||
|
|
"description": {
|
|||
|
|
"employee_name": "刘芳",
|
|||
|
|
"department": "人事部",
|
|||
|
|
"error": "页面白屏,控制台报500错误",
|
|||
|
|
"affected_count": 15,
|
|||
|
|
},
|
|||
|
|
"status": "pending",
|
|||
|
|
"assigned_agent_id": "agent-001",
|
|||
|
|
"corp_id": "ww1234567890",
|
|||
|
|
"created_at": "2026-06-05T11:30:00Z",
|
|||
|
|
"updated_at": "2026-06-05T11:30:00Z",
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"id": "todo-009",
|
|||
|
|
"type": "ticket",
|
|||
|
|
"title": "WiFi 无法连接 — 研发部开放区",
|
|||
|
|
"priority": "urgent",
|
|||
|
|
"description": {
|
|||
|
|
"employee_name": "陈明",
|
|||
|
|
"department": "研发部",
|
|||
|
|
"error": "获取IP失败,提示无法连接到此网络",
|
|||
|
|
"location": "3楼开放区",
|
|||
|
|
},
|
|||
|
|
"status": "pending",
|
|||
|
|
"assigned_agent_id": "agent-001",
|
|||
|
|
"corp_id": "ww1234567890",
|
|||
|
|
"created_at": "2026-06-06T08:00:00Z",
|
|||
|
|
"updated_at": "2026-06-06T08:00:00Z",
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"id": "todo-017",
|
|||
|
|
"type": "ticket",
|
|||
|
|
"title": "鼠标失灵 — 行政部周婷",
|
|||
|
|
"priority": "normal",
|
|||
|
|
"description": {
|
|||
|
|
"employee_name": "周婷",
|
|||
|
|
"department": "行政部",
|
|||
|
|
"error": "USB鼠标间歇性失灵,更换接口无效",
|
|||
|
|
"os": "Windows 11",
|
|||
|
|
},
|
|||
|
|
"status": "pending",
|
|||
|
|
"assigned_agent_id": "agent-001",
|
|||
|
|
"corp_id": "ww1234567890",
|
|||
|
|
"created_at": "2026-06-06T09:00:00Z",
|
|||
|
|
"updated_at": "2026-06-06T09:00:00Z",
|
|||
|
|
},
|
|||
|
|
# 进行中
|
|||
|
|
{
|
|||
|
|
"id": "todo-004",
|
|||
|
|
"type": "ticket",
|
|||
|
|
"title": "邮箱容量告警 — 市场部王强",
|
|||
|
|
"priority": "high",
|
|||
|
|
"description": {
|
|||
|
|
"employee_name": "王强",
|
|||
|
|
"department": "市场部",
|
|||
|
|
"current_usage": "4.8GB / 5GB",
|
|||
|
|
"action": "协助清理或申请扩容",
|
|||
|
|
},
|
|||
|
|
"status": "processing",
|
|||
|
|
"assigned_agent_id": "agent-001",
|
|||
|
|
"corp_id": "ww1234567890",
|
|||
|
|
"created_at": "2026-06-04T14:30:00Z",
|
|||
|
|
"updated_at": "2026-06-05T08:00:00Z",
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"id": "todo-010",
|
|||
|
|
"type": "ticket",
|
|||
|
|
"title": "ERP系统响应慢 — 全公司反馈",
|
|||
|
|
"priority": "high",
|
|||
|
|
"description": {
|
|||
|
|
"employee_name": "多个员工",
|
|||
|
|
"department": "全公司",
|
|||
|
|
"error": "ERP首页加载超过15秒",
|
|||
|
|
"affected_count": 50,
|
|||
|
|
},
|
|||
|
|
"status": "processing",
|
|||
|
|
"assigned_agent_id": "agent-001",
|
|||
|
|
"corp_id": "ww1234567890",
|
|||
|
|
"created_at": "2026-06-05T10:00:00Z",
|
|||
|
|
"updated_at": "2026-06-05T15:00:00Z",
|
|||
|
|
},
|
|||
|
|
# 已完成
|
|||
|
|
{
|
|||
|
|
"id": "todo-011",
|
|||
|
|
"type": "ticket",
|
|||
|
|
"title": "打印机驱动安装 — 市场部赵敏",
|
|||
|
|
"priority": "normal",
|
|||
|
|
"description": {
|
|||
|
|
"employee_name": "赵敏",
|
|||
|
|
"department": "市场部",
|
|||
|
|
"device_model": "Canon LBP2900",
|
|||
|
|
"solution": "从官网下载驱动并安装,测试打印正常",
|
|||
|
|
},
|
|||
|
|
"status": "resolved",
|
|||
|
|
"assigned_agent_id": "agent-001",
|
|||
|
|
"corp_id": "ww1234567890",
|
|||
|
|
"created_at": "2026-06-01T09:00:00Z",
|
|||
|
|
"updated_at": "2026-06-02T16:00:00Z",
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
# ========== 审批(approval)==========
|
|||
|
|
# 待处理
|
|||
|
|
{
|
|||
|
|
"id": "todo-002",
|
|||
|
|
"type": "approval",
|
|||
|
|
"title": "软件安装审批 — 设计部PS申请",
|
|||
|
|
"priority": "high",
|
|||
|
|
"description": {
|
|||
|
|
"employee_name": "李娜",
|
|||
|
|
"department": "设计部",
|
|||
|
|
"software": "Adobe Photoshop 2026",
|
|||
|
|
"license_type": "企业许可",
|
|||
|
|
},
|
|||
|
|
"status": "pending",
|
|||
|
|
"assigned_agent_id": "agent-001",
|
|||
|
|
"corp_id": "ww1234567890",
|
|||
|
|
"created_at": "2026-06-05T10:20:00Z",
|
|||
|
|
"updated_at": "2026-06-05T10:20:00Z",
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"id": "todo-005",
|
|||
|
|
"type": "approval",
|
|||
|
|
"title": "权限升级审批 — 研发部数据库访问",
|
|||
|
|
"priority": "high",
|
|||
|
|
"description": {
|
|||
|
|
"employee_name": "陈明",
|
|||
|
|
"department": "研发部",
|
|||
|
|
"target_system": "生产数据库",
|
|||
|
|
"access_level": "只读",
|
|||
|
|
"approver": "研发总监",
|
|||
|
|
},
|
|||
|
|
"status": "pending",
|
|||
|
|
"assigned_agent_id": "agent-001",
|
|||
|
|
"corp_id": "ww1234567890",
|
|||
|
|
"created_at": "2026-06-05T08:45:00Z",
|
|||
|
|
"updated_at": "2026-06-05T08:45:00Z",
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"id": "todo-008",
|
|||
|
|
"type": "approval",
|
|||
|
|
"title": "新员工设备采购审批 — Q3批次",
|
|||
|
|
"priority": "normal",
|
|||
|
|
"description": {
|
|||
|
|
"batch": "Q3新员工",
|
|||
|
|
"count": 5,
|
|||
|
|
"items": ["笔记本x5", "显示器x5", "键鼠套装x5"],
|
|||
|
|
"budget": "65,000元",
|
|||
|
|
},
|
|||
|
|
"status": "pending",
|
|||
|
|
"assigned_agent_id": "agent-001",
|
|||
|
|
"corp_id": "ww1234567890",
|
|||
|
|
"created_at": "2026-06-05T07:00:00Z",
|
|||
|
|
"updated_at": "2026-06-05T07:00:00Z",
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"id": "todo-018",
|
|||
|
|
"type": "approval",
|
|||
|
|
"title": "弹性福利审批 — 全体员工Q3",
|
|||
|
|
"priority": "normal",
|
|||
|
|
"description": {
|
|||
|
|
"applicant": "人事部",
|
|||
|
|
"type": "弹性福利",
|
|||
|
|
"budget_per_person": "3000元",
|
|||
|
|
"total_count": 120,
|
|||
|
|
},
|
|||
|
|
"status": "pending",
|
|||
|
|
"assigned_agent_id": "agent-001",
|
|||
|
|
"corp_id": "ww1234567890",
|
|||
|
|
"created_at": "2026-06-06T07:00:00Z",
|
|||
|
|
"updated_at": "2026-06-06T07:00:00Z",
|
|||
|
|
},
|
|||
|
|
# 进行中
|
|||
|
|
{
|
|||
|
|
"id": "todo-012",
|
|||
|
|
"type": "approval",
|
|||
|
|
"title": "预算审批 — IT部Q3采购",
|
|||
|
|
"priority": "high",
|
|||
|
|
"description": {
|
|||
|
|
"department": "IT部",
|
|||
|
|
"amount": "280,000元",
|
|||
|
|
"items": ["服务器x2", "防火墙x2", "交换机x4"],
|
|||
|
|
"approver": "CFO",
|
|||
|
|
},
|
|||
|
|
"status": "processing",
|
|||
|
|
"assigned_agent_id": "agent-001",
|
|||
|
|
"corp_id": "ww1234567890",
|
|||
|
|
"created_at": "2026-06-04T09:00:00Z",
|
|||
|
|
"updated_at": "2026-06-05T14:00:00Z",
|
|||
|
|
},
|
|||
|
|
# 已完成
|
|||
|
|
{
|
|||
|
|
"id": "todo-013",
|
|||
|
|
"type": "approval",
|
|||
|
|
"title": "会议室预订审批 — 销售部Q3客户拜访",
|
|||
|
|
"priority": "normal",
|
|||
|
|
"description": {
|
|||
|
|
"employee_name": "刘军",
|
|||
|
|
"department": "销售部",
|
|||
|
|
"room": "5楼大会议室",
|
|||
|
|
"time": "2026-06-10 14:00-17:00",
|
|||
|
|
"result": "已批准",
|
|||
|
|
},
|
|||
|
|
"status": "resolved",
|
|||
|
|
"assigned_agent_id": "agent-001",
|
|||
|
|
"corp_id": "ww1234567890",
|
|||
|
|
"created_at": "2026-05-28T08:00:00Z",
|
|||
|
|
"updated_at": "2026-05-29T10:00:00Z",
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
# ========== 设备(device)==========
|
|||
|
|
# 待处理
|
|||
|
|
{
|
|||
|
|
"id": "todo-003",
|
|||
|
|
"type": "device",
|
|||
|
|
"title": "工位打印机故障 — 3楼A区",
|
|||
|
|
"priority": "normal",
|
|||
|
|
"description": {
|
|||
|
|
"location": "3楼A区打印间",
|
|||
|
|
"device_model": "HP LaserJet Pro M404",
|
|||
|
|
"issue": "卡纸,无法打印",
|
|||
|
|
},
|
|||
|
|
"status": "pending",
|
|||
|
|
"assigned_agent_id": "agent-001",
|
|||
|
|
"corp_id": "ww1234567890",
|
|||
|
|
"created_at": "2026-06-05T11:05:00Z",
|
|||
|
|
"updated_at": "2026-06-05T11:05:00Z",
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"id": "todo-014",
|
|||
|
|
"type": "device",
|
|||
|
|
"title": "核心交换机故障 — 机房",
|
|||
|
|
"priority": "urgent",
|
|||
|
|
"description": {
|
|||
|
|
"location": "机房A区",
|
|||
|
|
"device_model": "Cisco Catalyst 9300",
|
|||
|
|
"issue": "端口3-12全部down,影响2楼所有工位",
|
|||
|
|
"affected_count": 45,
|
|||
|
|
},
|
|||
|
|
"status": "pending",
|
|||
|
|
"assigned_agent_id": "agent-001",
|
|||
|
|
"corp_id": "ww1234567890",
|
|||
|
|
"created_at": "2026-06-06T00:30:00Z",
|
|||
|
|
"updated_at": "2026-06-06T00:30:00Z",
|
|||
|
|
},
|
|||
|
|
# 进行中
|
|||
|
|
{
|
|||
|
|
"id": "todo-006",
|
|||
|
|
"type": "device",
|
|||
|
|
"title": "会议室投影仪维修 — 5楼大会议室",
|
|||
|
|
"priority": "normal",
|
|||
|
|
"description": {
|
|||
|
|
"location": "5楼大会议室",
|
|||
|
|
"device_model": "Epson EB-X51",
|
|||
|
|
"issue": "投影模糊,可能灯泡老化",
|
|||
|
|
},
|
|||
|
|
"status": "processing",
|
|||
|
|
"assigned_agent_id": "agent-001",
|
|||
|
|
"corp_id": "ww1234567890",
|
|||
|
|
"created_at": "2026-06-03T16:00:00Z",
|
|||
|
|
"updated_at": "2026-06-04T10:00:00Z",
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"id": "todo-015",
|
|||
|
|
"type": "device",
|
|||
|
|
"title": "服务器硬盘更换 — 虚拟化集群",
|
|||
|
|
"priority": "high",
|
|||
|
|
"description": {
|
|||
|
|
"location": "机房B区",
|
|||
|
|
"device_model": "Dell R740",
|
|||
|
|
"issue": "硬盘预警,需更换并做好数据迁移",
|
|||
|
|
"affected_vms": 12,
|
|||
|
|
},
|
|||
|
|
"status": "processing",
|
|||
|
|
"assigned_agent_id": "agent-001",
|
|||
|
|
"corp_id": "ww1234567890",
|
|||
|
|
"created_at": "2026-06-05T09:00:00Z",
|
|||
|
|
"updated_at": "2026-06-05T16:00:00Z",
|
|||
|
|
},
|
|||
|
|
# 已完成
|
|||
|
|
{
|
|||
|
|
"id": "todo-016",
|
|||
|
|
"type": "device",
|
|||
|
|
"title": "员工笔记本磁盘扩容 — 人事部吴婷",
|
|||
|
|
"priority": "normal",
|
|||
|
|
"description": {
|
|||
|
|
"employee_name": "吴婷",
|
|||
|
|
"department": "人事部",
|
|||
|
|
"device_model": "ThinkPad X1 Carbon",
|
|||
|
|
"solution": "更换1TB SSD,克隆系统,测试正常",
|
|||
|
|
},
|
|||
|
|
"status": "resolved",
|
|||
|
|
"assigned_agent_id": "agent-001",
|
|||
|
|
"corp_id": "ww1234567890",
|
|||
|
|
"created_at": "2026-05-20T13:00:00Z",
|
|||
|
|
"updated_at": "2026-05-22T17:00:00Z",
|
|||
|
|
},
|
|||
|
|
]
|
|||
|
|
|
|||
|
|
|
|||
|
|
# --------------------------------------------------------------------------
|
|||
|
|
# API 接口
|
|||
|
|
# --------------------------------------------------------------------------
|
|||
|
|
|
|||
|
|
@router.get("")
|
|||
|
|
async def list_todo_items(
|
|||
|
|
status: Optional[str] = None,
|
|||
|
|
priority: Optional[str] = None,
|
|||
|
|
):
|
|||
|
|
"""获取当前坐席待办列表。
|
|||
|
|
|
|||
|
|
支持按状态和优先级过滤。
|
|||
|
|
"""
|
|||
|
|
items = MOCK_TODO_ITEMS
|
|||
|
|
|
|||
|
|
# 按状态过滤
|
|||
|
|
if status:
|
|||
|
|
items = [item for item in items if item["status"] == status]
|
|||
|
|
|
|||
|
|
# 按优先级过滤
|
|||
|
|
if priority:
|
|||
|
|
items = [item for item in items if item["priority"] == priority]
|
|||
|
|
|
|||
|
|
# 按优先级排序:urgent → high → normal
|
|||
|
|
priority_order = {"urgent": 0, "high": 1, "normal": 2}
|
|||
|
|
items = sorted(items, key=lambda x: priority_order.get(x["priority"], 3))
|
|||
|
|
|
|||
|
|
return success_response(data={
|
|||
|
|
"items": [TodoItemResponse(**item).model_dump() for item in items],
|
|||
|
|
"total": len(items),
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
|
|||
|
|
@router.get("/{item_id}")
|
|||
|
|
async def get_todo_item(item_id: str):
|
|||
|
|
"""获取待办事项详情。"""
|
|||
|
|
for item in MOCK_TODO_ITEMS:
|
|||
|
|
if item["id"] == item_id:
|
|||
|
|
return success_response(data=TodoItemResponse(**item).model_dump())
|
|||
|
|
raise AppException(code=1003, message=f"待办事项 {item_id} 不存在")
|
|||
|
|
|
|||
|
|
|
|||
|
|
@router.put("/{item_id}/status")
|
|||
|
|
async def update_todo_item_status(item_id: str, request: TodoStatusUpdateRequest):
|
|||
|
|
"""更新待办事项状态。"""
|
|||
|
|
# 校验状态值
|
|||
|
|
valid_statuses = {"pending", "processing", "resolved"}
|
|||
|
|
if request.status not in valid_statuses:
|
|||
|
|
raise HTTPException(
|
|||
|
|
status_code=400,
|
|||
|
|
detail=f"无效的状态值: {request.status},合法值为: {valid_statuses}",
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
for item in MOCK_TODO_ITEMS:
|
|||
|
|
if item["id"] == item_id:
|
|||
|
|
item["status"] = request.status
|
|||
|
|
item["updated_at"] = datetime.now().isoformat()
|
|||
|
|
return success_response(data=TodoItemResponse(**item).model_dump())
|
|||
|
|
|
|||
|
|
raise AppException(code=1003, message=f"待办事项 {item_id} 不存在")
|