feat: 娣诲姞澶氫釜鏂板姛鑳藉拰淇 - 鍖呮嫭鐢ㄦ埛绠$悊銆佹暟鎹簱杩佺Щ銆丟it鎺ㄩ€佸伐鍏风瓑
This commit is contained in:
Binary file not shown.
BIN
src/core/__pycache__/workorder_permissions.cpython-311.pyc
Normal file
BIN
src/core/__pycache__/workorder_permissions.cpython-311.pyc
Normal file
Binary file not shown.
@@ -8,7 +8,7 @@ Base = declarative_base()
|
||||
class WorkOrder(Base):
|
||||
"""工单模型"""
|
||||
__tablename__ = "work_orders"
|
||||
|
||||
|
||||
id = Column(Integer, primary_key=True)
|
||||
order_id = Column(String(50), unique=True, nullable=False)
|
||||
title = Column(String(200), nullable=False)
|
||||
@@ -20,13 +20,13 @@ class WorkOrder(Base):
|
||||
updated_at = Column(DateTime, default=datetime.now, onupdate=datetime.now)
|
||||
resolution = Column(Text)
|
||||
satisfaction_score = Column(Float)
|
||||
|
||||
|
||||
# 飞书集成字段
|
||||
feishu_record_id = Column(String(100), unique=True, nullable=True) # 飞书记录ID
|
||||
assignee = Column(String(100), nullable=True) # 负责人
|
||||
solution = Column(Text, nullable=True) # 解决方案
|
||||
ai_suggestion = Column(Text, nullable=True) # AI建议
|
||||
|
||||
|
||||
# 扩展飞书字段
|
||||
source = Column(String(50), nullable=True) # 来源(Mail, Telegram bot等)
|
||||
module = Column(String(100), nullable=True) # 模块(local O&M, OTA等)
|
||||
@@ -40,14 +40,23 @@ class WorkOrder(Base):
|
||||
parent_record = Column(String(100), nullable=True) # 父记录
|
||||
has_updated_same_day = Column(String(50), nullable=True) # 是否同日更新
|
||||
operating_time = Column(String(100), nullable=True) # 操作时间
|
||||
|
||||
|
||||
# 工单分发和权限管理字段
|
||||
assigned_module = Column(String(50), nullable=True) # 分配的模块(TBOX、OTA等)
|
||||
module_owner = Column(String(100), nullable=True) # 业务接口人/模块负责人
|
||||
dispatcher = Column(String(100), nullable=True) # 分发人(运维人员)
|
||||
dispatch_time = Column(DateTime, nullable=True) # 分发时间
|
||||
region = Column(String(50), nullable=True) # 区域(overseas/domestic)- 用于区分海外/国内
|
||||
|
||||
# 关联对话记录
|
||||
conversations = relationship("Conversation", back_populates="work_order")
|
||||
# 关联处理过程记录
|
||||
process_history = relationship("WorkOrderProcessHistory", back_populates="work_order", order_by="WorkOrderProcessHistory.process_time")
|
||||
|
||||
class Conversation(Base):
|
||||
"""对话记录模型"""
|
||||
__tablename__ = "conversations"
|
||||
|
||||
|
||||
id = Column(Integer, primary_key=True)
|
||||
work_order_id = Column(Integer, ForeignKey("work_orders.id"))
|
||||
user_message = Column(Text, nullable=False)
|
||||
@@ -56,13 +65,13 @@ class Conversation(Base):
|
||||
confidence_score = Column(Float)
|
||||
knowledge_used = Column(Text) # 使用的知识库条目
|
||||
response_time = Column(Float) # 响应时间(秒)
|
||||
|
||||
|
||||
work_order = relationship("WorkOrder", back_populates="conversations")
|
||||
|
||||
class KnowledgeEntry(Base):
|
||||
"""知识库条目模型"""
|
||||
__tablename__ = "knowledge_entries"
|
||||
|
||||
|
||||
id = Column(Integer, primary_key=True)
|
||||
question = Column(Text, nullable=False)
|
||||
answer = Column(Text, nullable=False)
|
||||
@@ -80,7 +89,7 @@ class KnowledgeEntry(Base):
|
||||
class VehicleData(Base):
|
||||
"""车辆实时数据模型"""
|
||||
__tablename__ = "vehicle_data"
|
||||
|
||||
|
||||
id = Column(Integer, primary_key=True)
|
||||
vehicle_id = Column(String(50), nullable=False) # 车辆ID
|
||||
vehicle_vin = Column(String(17)) # 车架号
|
||||
@@ -88,7 +97,7 @@ class VehicleData(Base):
|
||||
data_value = Column(Text, nullable=False) # 数据值(JSON格式)
|
||||
timestamp = Column(DateTime, default=datetime.now) # 数据时间戳
|
||||
is_active = Column(Boolean, default=True) # 是否有效
|
||||
|
||||
|
||||
# 索引
|
||||
__table_args__ = (
|
||||
{'extend_existing': True}
|
||||
@@ -97,7 +106,7 @@ class VehicleData(Base):
|
||||
class Analytics(Base):
|
||||
"""分析统计模型"""
|
||||
__tablename__ = "analytics"
|
||||
|
||||
|
||||
id = Column(Integer, primary_key=True)
|
||||
date = Column(DateTime, nullable=False)
|
||||
total_orders = Column(Integer, default=0)
|
||||
@@ -111,7 +120,7 @@ class Analytics(Base):
|
||||
class Alert(Base):
|
||||
"""预警模型"""
|
||||
__tablename__ = "alerts"
|
||||
|
||||
|
||||
id = Column(Integer, primary_key=True)
|
||||
rule_name = Column(String(100), nullable=False)
|
||||
alert_type = Column(String(50), nullable=False)
|
||||
@@ -126,7 +135,7 @@ class Alert(Base):
|
||||
class WorkOrderSuggestion(Base):
|
||||
"""工单AI建议与人工描述表"""
|
||||
__tablename__ = "work_order_suggestions"
|
||||
|
||||
|
||||
id = Column(Integer, primary_key=True)
|
||||
work_order_id = Column(Integer, ForeignKey("work_orders.id"), nullable=False)
|
||||
ai_suggestion = Column(Text)
|
||||
@@ -136,3 +145,31 @@ class WorkOrderSuggestion(Base):
|
||||
use_human_resolution = Column(Boolean, default=False) # 是否使用人工描述入库
|
||||
created_at = Column(DateTime, default=datetime.now)
|
||||
updated_at = Column(DateTime, default=datetime.now, onupdate=datetime.now)
|
||||
|
||||
class WorkOrderProcessHistory(Base):
|
||||
"""工单处理过程记录表"""
|
||||
__tablename__ = "work_order_process_history"
|
||||
|
||||
id = Column(Integer, primary_key=True)
|
||||
work_order_id = Column(Integer, ForeignKey("work_orders.id"), nullable=False)
|
||||
|
||||
# 处理人员信息
|
||||
processor_name = Column(String(100), nullable=False) # 处理人员姓名
|
||||
processor_role = Column(String(50), nullable=True) # 处理人员角色(运维、业务方等)
|
||||
processor_region = Column(String(50), nullable=True) # 处理人员区域(overseas/domestic)
|
||||
|
||||
# 处理内容
|
||||
process_content = Column(Text, nullable=False) # 处理内容/操作描述
|
||||
action_type = Column(String(50), nullable=False) # 操作类型(dispatch、process、close、reassign等)
|
||||
|
||||
# 处理结果
|
||||
previous_status = Column(String(50), nullable=True) # 处理前的状态
|
||||
new_status = Column(String(50), nullable=True) # 处理后的状态
|
||||
assigned_module = Column(String(50), nullable=True) # 分配的模块(如果是分发操作)
|
||||
|
||||
# 时间戳
|
||||
process_time = Column(DateTime, default=datetime.now, nullable=False) # 处理时间
|
||||
created_at = Column(DateTime, default=datetime.now)
|
||||
|
||||
# 关联工单
|
||||
work_order = relationship("WorkOrder", back_populates="process_history")
|
||||
|
||||
231
src/core/workorder_permissions.py
Normal file
231
src/core/workorder_permissions.py
Normal file
@@ -0,0 +1,231 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
工单权限管理模块
|
||||
实现基于角色的访问控制(RBAC)和工单分发流程
|
||||
"""
|
||||
|
||||
import logging
|
||||
from typing import List, Dict, Optional, Set
|
||||
from enum import Enum
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
class UserRole(Enum):
|
||||
"""用户角色枚举"""
|
||||
# 属地运维(海外/国内)
|
||||
OVERSEAS_OPS = "overseas_ops" # 海外属地运维
|
||||
DOMESTIC_OPS = "domestic_ops" # 国内属地运维
|
||||
|
||||
# 业务方接口人(各模块负责人)
|
||||
TBOX_OWNER = "tbox_owner" # TBOX模块负责人
|
||||
OTA_OWNER = "ota_owner" # OTA模块负责人
|
||||
DMC_OWNER = "dmc_owner" # DMC模块负责人
|
||||
MES_OWNER = "mes_owner" # MES模块负责人
|
||||
APP_OWNER = "app_owner" # APP模块负责人
|
||||
PKI_OWNER = "pki_owner" # PKI模块负责人
|
||||
TSP_OWNER = "tsp_owner" # TSP模块负责人
|
||||
|
||||
# 系统角色
|
||||
ADMIN = "admin" # 系统管理员
|
||||
VIEWER = "viewer" # 只读用户
|
||||
|
||||
class WorkOrderModule(Enum):
|
||||
"""工单模块枚举"""
|
||||
TBOX = "TBOX"
|
||||
OTA = "OTA"
|
||||
DMC = "DMC"
|
||||
MES = "MES"
|
||||
APP = "APP"
|
||||
PKI = "PKI"
|
||||
TSP = "TSP"
|
||||
LOCAL_OPS = "local_ops" # 属地运维处理
|
||||
UNASSIGNED = "unassigned" # 未分配
|
||||
|
||||
class WorkOrderStatus:
|
||||
"""工单状态常量"""
|
||||
PENDING = "pending" # 待处理
|
||||
ASSIGNED = "assigned" # 已分配
|
||||
IN_PROGRESS = "in_progress" # 处理中
|
||||
RESOLVED = "resolved" # 已解决
|
||||
CLOSED = "closed" # 已关闭
|
||||
|
||||
class WorkOrderPermissionManager:
|
||||
"""工单权限管理器"""
|
||||
|
||||
# 所有模块集合(供属地运维和管理员使用)
|
||||
ALL_MODULES = {
|
||||
WorkOrderModule.TBOX, WorkOrderModule.OTA, WorkOrderModule.DMC,
|
||||
WorkOrderModule.MES, WorkOrderModule.APP, WorkOrderModule.PKI,
|
||||
WorkOrderModule.TSP, WorkOrderModule.LOCAL_OPS
|
||||
}
|
||||
|
||||
# 角色到模块的映射
|
||||
ROLE_MODULE_MAP = {
|
||||
UserRole.TBOX_OWNER: {WorkOrderModule.TBOX},
|
||||
UserRole.OTA_OWNER: {WorkOrderModule.OTA},
|
||||
UserRole.DMC_OWNER: {WorkOrderModule.DMC},
|
||||
UserRole.MES_OWNER: {WorkOrderModule.MES},
|
||||
UserRole.APP_OWNER: {WorkOrderModule.APP},
|
||||
UserRole.PKI_OWNER: {WorkOrderModule.PKI},
|
||||
UserRole.TSP_OWNER: {WorkOrderModule.TSP},
|
||||
UserRole.OVERSEAS_OPS: ALL_MODULES, # 可访问所有模块
|
||||
UserRole.DOMESTIC_OPS: ALL_MODULES, # 可访问所有模块
|
||||
UserRole.ADMIN: ALL_MODULES, # 管理员可访问所有
|
||||
UserRole.VIEWER: set(), # 只读,由其他逻辑控制
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
def can_view_all_workorders(role: UserRole) -> bool:
|
||||
"""判断角色是否可以查看所有工单(属地运维和管理员)"""
|
||||
return role in [UserRole.OVERSEAS_OPS, UserRole.DOMESTIC_OPS, UserRole.ADMIN]
|
||||
|
||||
@staticmethod
|
||||
def get_accessible_modules(role: UserRole) -> Set[WorkOrderModule]:
|
||||
"""获取角色可访问的模块列表"""
|
||||
return WorkOrderPermissionManager.ROLE_MODULE_MAP.get(role, set())
|
||||
|
||||
@staticmethod
|
||||
def can_access_module(role: UserRole, module: WorkOrderModule) -> bool:
|
||||
"""判断角色是否可以访问指定模块"""
|
||||
accessible_modules = WorkOrderPermissionManager.get_accessible_modules(role)
|
||||
|
||||
# 属地运维和管理员可以访问所有模块
|
||||
if WorkOrderPermissionManager.can_view_all_workorders(role):
|
||||
return True
|
||||
|
||||
# 业务方只能访问自己的模块
|
||||
return module in accessible_modules
|
||||
|
||||
@staticmethod
|
||||
def can_dispatch_workorder(role: UserRole) -> bool:
|
||||
"""判断角色是否可以进行工单分发(属地运维和管理员)"""
|
||||
return role in [UserRole.OVERSEAS_OPS, UserRole.DOMESTIC_OPS, UserRole.ADMIN]
|
||||
|
||||
@staticmethod
|
||||
def can_update_workorder(role: UserRole, workorder_module: Optional[WorkOrderModule],
|
||||
assigned_to_module: Optional[WorkOrderModule]) -> bool:
|
||||
"""判断角色是否可以更新工单"""
|
||||
# 管理员和属地运维可以更新所有工单
|
||||
if WorkOrderPermissionManager.can_view_all_workorders(role):
|
||||
return True
|
||||
|
||||
# 业务方只能更新分配给自己的模块的工单
|
||||
if workorder_module and assigned_to_module:
|
||||
accessible_modules = WorkOrderPermissionManager.get_accessible_modules(role)
|
||||
return workorder_module in accessible_modules and workorder_module == assigned_to_module
|
||||
|
||||
return False
|
||||
|
||||
@staticmethod
|
||||
def filter_workorders_by_permission(role: UserRole, workorders: List[Dict]) -> List[Dict]:
|
||||
"""根据权限过滤工单列表"""
|
||||
if WorkOrderPermissionManager.can_view_all_workorders(role):
|
||||
# 属地运维和管理员可以看到所有工单
|
||||
return workorders
|
||||
|
||||
# 业务方只能看到自己模块的工单
|
||||
accessible_modules = WorkOrderPermissionManager.get_accessible_modules(role)
|
||||
filtered = []
|
||||
|
||||
for wo in workorders:
|
||||
module_str = wo.get("module") or wo.get("assigned_module")
|
||||
if module_str:
|
||||
try:
|
||||
module = WorkOrderModule(module_str)
|
||||
if module in accessible_modules:
|
||||
filtered.append(wo)
|
||||
except ValueError:
|
||||
# 如果模块值不在枚举中,跳过
|
||||
continue
|
||||
else:
|
||||
# 未分配的工单,业务方看不到
|
||||
pass
|
||||
|
||||
return filtered
|
||||
|
||||
class WorkOrderDispatchManager:
|
||||
"""工单分发管理器"""
|
||||
|
||||
# 模块到业务接口人的映射(可以动态配置)
|
||||
MODULE_OWNER_MAP = {
|
||||
WorkOrderModule.TBOX: "TBOX业务接口人",
|
||||
WorkOrderModule.OTA: "OTA业务接口人",
|
||||
WorkOrderModule.DMC: "DMC业务接口人",
|
||||
WorkOrderModule.MES: "MES业务接口人",
|
||||
WorkOrderModule.APP: "APP业务接口人",
|
||||
WorkOrderModule.PKI: "PKI业务接口人",
|
||||
WorkOrderModule.TSP: "TSP业务接口人",
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
def get_module_owner(module: WorkOrderModule) -> str:
|
||||
"""获取模块的业务接口人"""
|
||||
return WorkOrderDispatchManager.MODULE_OWNER_MAP.get(module, "未指定")
|
||||
|
||||
@staticmethod
|
||||
def dispatch_workorder(workorder_id: int, target_module: WorkOrderModule,
|
||||
dispatcher_role: UserRole, dispatcher_name: str) -> Dict:
|
||||
"""
|
||||
分发工单到指定模块
|
||||
|
||||
Args:
|
||||
workorder_id: 工单ID
|
||||
target_module: 目标模块
|
||||
dispatcher_role: 分发者角色(必须是运维或管理员)
|
||||
dispatcher_name: 分发者姓名
|
||||
|
||||
Returns:
|
||||
分发结果
|
||||
"""
|
||||
# 检查分发权限
|
||||
if not WorkOrderPermissionManager.can_dispatch_workorder(dispatcher_role):
|
||||
return {
|
||||
"success": False,
|
||||
"error": "无权进行工单分发,只有属地运维和管理员可以分发工单"
|
||||
}
|
||||
|
||||
# 获取模块负责人
|
||||
module_owner = WorkOrderDispatchManager.get_module_owner(target_module)
|
||||
|
||||
# 这里应该更新数据库中的工单信息
|
||||
# 实际实现时需要调用数据库更新逻辑
|
||||
return {
|
||||
"success": True,
|
||||
"message": f"工单已分发到{target_module.value}模块",
|
||||
"assigned_module": target_module.value,
|
||||
"module_owner": module_owner,
|
||||
"dispatcher": dispatcher_name,
|
||||
"dispatcher_role": dispatcher_role.value
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
def suggest_module(description: str, title: str = "") -> Optional[WorkOrderModule]:
|
||||
"""
|
||||
根据工单描述建议分配模块(可以使用AI分析)
|
||||
|
||||
Args:
|
||||
description: 工单描述
|
||||
title: 工单标题
|
||||
|
||||
Returns:
|
||||
建议的模块
|
||||
"""
|
||||
# 简单的关键词匹配(实际可以使用AI分析)
|
||||
text = (title + " " + description).lower()
|
||||
|
||||
keyword_module_map = {
|
||||
WorkOrderModule.TBOX: ["tbox", "telematics", "车载", "车联网"],
|
||||
WorkOrderModule.OTA: ["ota", "over-the-air", "升级", "update"],
|
||||
WorkOrderModule.DMC: ["dmc", "device management", "设备管理"],
|
||||
WorkOrderModule.MES: ["mes", "manufacturing", "制造"],
|
||||
WorkOrderModule.APP: ["app", "application", "应用", "remote control"],
|
||||
WorkOrderModule.PKI: ["pki", "certificate", "证书"],
|
||||
WorkOrderModule.TSP: ["tsp", "service", "服务"],
|
||||
}
|
||||
|
||||
for module, keywords in keyword_module_map.items():
|
||||
for keyword in keywords:
|
||||
if keyword in text:
|
||||
return module
|
||||
|
||||
return WorkOrderModule.UNASSIGNED
|
||||
Reference in New Issue
Block a user