from sqlalchemy import Column, Integer, String, Text, DateTime, Float, Boolean, ForeignKey, Index from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.orm import relationship from datetime import datetime import hashlib Base = declarative_base() # 默认租户ID,单租户部署时使用 DEFAULT_TENANT = "default" class Tenant(Base): """租户模型 — 管理多租户(市场)""" __tablename__ = "tenants" id = Column(Integer, primary_key=True) tenant_id = Column(String(50), unique=True, nullable=False) # 唯一标识,如 market_a name = Column(String(100), nullable=False) # 显示名称,如 "市场A" description = Column(Text, nullable=True) is_active = Column(Boolean, default=True) created_at = Column(DateTime, default=datetime.now) updated_at = Column(DateTime, default=datetime.now, onupdate=datetime.now) # 租户级配置:飞书 app 凭证、LLM 参数等(JSON 格式) config = Column(Text, nullable=True) def to_dict(self): import json return { 'id': self.id, 'tenant_id': self.tenant_id, 'name': self.name, 'description': self.description, 'is_active': self.is_active, 'config': json.loads(self.config) if self.config else {}, 'created_at': self.created_at.isoformat() if self.created_at else None, 'updated_at': self.updated_at.isoformat() if self.updated_at else None, } class WorkOrder(Base): """工单模型""" __tablename__ = "work_orders" id = Column(Integer, primary_key=True) tenant_id = Column(String(50), nullable=False, default=DEFAULT_TENANT, index=True) order_id = Column(String(50), unique=True, nullable=False) title = Column(String(200), nullable=False) description = Column(Text, nullable=False) category = Column(String(100), nullable=False) priority = Column(String(20), nullable=False) status = Column(String(20), nullable=False) created_at = Column(DateTime, default=datetime.now) 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等) created_by = Column(String(100), nullable=True) # 创建人 wilfulness = Column(String(100), nullable=True) # 责任人 date_of_close = Column(DateTime, nullable=True) # 关闭日期 vehicle_type = Column(String(100), nullable=True) # 车型 vin_sim = Column(String(50), nullable=True) # 车架号/SIM app_remote_control_version = Column(String(100), nullable=True) # 应用远程控制版本 hmi_sw = Column(String(100), nullable=True) # HMI软件版本 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)- 用于区分海外/国内 # 系统优化字段 processing_efficiency = Column(Float) # 处理效率 resource_usage = Column(Text) # 资源使用情况 # 关联对话记录 conversations = relationship("Conversation", back_populates="work_order") # 关联处理过程记录 process_history = relationship("WorkOrderProcessHistory", back_populates="work_order", order_by="WorkOrderProcessHistory.process_time") class ChatSession(Base): """对话会话模型 — 将多轮对话组织为一个会话""" __tablename__ = "chat_sessions" id = Column(Integer, primary_key=True) tenant_id = Column(String(50), nullable=False, default=DEFAULT_TENANT, index=True) session_id = Column(String(100), unique=True, nullable=False) # 唯一会话标识 user_id = Column(String(100), nullable=True) # 用户标识 work_order_id = Column(Integer, ForeignKey("work_orders.id"), nullable=True) title = Column(String(200), nullable=True) # 会话标题(取首条消息摘要) status = Column(String(20), default="active") # active, ended message_count = Column(Integer, default=0) # 消息轮数 source = Column(String(100), nullable=True) # 来源:websocket, api, feishu_bot(group) 等 ip_address = Column(String(200), nullable=True) # IP地址或来源标识 created_at = Column(DateTime, default=datetime.now) updated_at = Column(DateTime, default=datetime.now, onupdate=datetime.now) ended_at = Column(DateTime, nullable=True) # 关联消息 messages = relationship("Conversation", back_populates="chat_session", order_by="Conversation.timestamp") def to_dict(self): return { 'id': self.id, 'session_id': self.session_id, 'user_id': self.user_id, 'work_order_id': self.work_order_id, 'title': self.title, 'status': self.status, 'message_count': self.message_count, 'source': self.source, 'ip_address': self.ip_address, 'created_at': self.created_at.isoformat() if self.created_at else None, 'updated_at': self.updated_at.isoformat() if self.updated_at else None, 'ended_at': self.ended_at.isoformat() if self.ended_at else None, } class Conversation(Base): """对话记录模型""" __tablename__ = "conversations" id = Column(Integer, primary_key=True) tenant_id = Column(String(50), nullable=False, default=DEFAULT_TENANT, index=True) session_id = Column(String(100), ForeignKey("chat_sessions.session_id"), nullable=True) # 关联会话 work_order_id = Column(Integer, ForeignKey("work_orders.id")) user_message = Column(Text, nullable=False) assistant_response = Column(Text, nullable=False) timestamp = Column(DateTime, default=datetime.now) confidence_score = Column(Float) knowledge_used = Column(Text) # 使用的知识库条目 response_time = Column(Float) # 响应时间(秒) ip_address = Column(String(200), nullable=True) # IP地址或来源标识(如 feishu:uid:name) invocation_method = Column(String(100), nullable=True) # 调用方式(websocket, api, feishu_bot(group) 等) # 系统优化字段 processing_time = Column(Float) # 处理时间 memory_usage = Column(Float) # 内存使用量 cpu_usage = Column(Float) # CPU使用率 work_order = relationship("WorkOrder", back_populates="conversations") chat_session = relationship("ChatSession", back_populates="messages") class KnowledgeEntry(Base): """知识库条目模型""" __tablename__ = "knowledge_entries" id = Column(Integer, primary_key=True) tenant_id = Column(String(50), nullable=False, default=DEFAULT_TENANT, index=True) question = Column(Text, nullable=False) answer = Column(Text, nullable=False) category = Column(String(100), nullable=False) confidence_score = Column(Float, default=0.0) usage_count = Column(Integer, default=0) created_at = Column(DateTime, default=datetime.now) updated_at = Column(DateTime, default=datetime.now, onupdate=datetime.now) is_active = Column(Boolean, default=True) is_verified = Column(Boolean, default=False) # 是否已验证 verified_by = Column(String(100)) # 验证人 verified_at = Column(DateTime) # 验证时间 vector_embedding = Column(Text) # 向量嵌入的JSON字符串 # 系统优化字段 search_frequency = Column(Integer, default=0) # 搜索频率 last_accessed = Column(DateTime) # 最后访问时间 relevance_score = Column(Float) # 相关性评分 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)) # 车架号 data_type = Column(String(50), nullable=False) # 数据类型(位置、状态、故障等) data_value = Column(Text, nullable=False) # 数据值(JSON格式) timestamp = Column(DateTime, default=datetime.now) # 数据时间戳 is_active = Column(Boolean, default=True) # 是否有效 # 索引 __table_args__ = ( {'extend_existing': True} ) class Analytics(Base): """分析统计模型""" __tablename__ = "analytics" id = Column(Integer, primary_key=True) tenant_id = Column(String(50), nullable=False, default=DEFAULT_TENANT, index=True) date = Column(DateTime, nullable=False) total_orders = Column(Integer, default=0) resolved_orders = Column(Integer, default=0) avg_resolution_time = Column(Float, default=0.0) satisfaction_avg = Column(Float, default=0.0) knowledge_hit_rate = Column(Float, default=0.0) category_distribution = Column(Text) # JSON格式的类别分布 created_at = Column(DateTime, default=datetime.now) # 分析增强字段 performance_score = Column(Float) # 性能评分 quality_metrics = Column(Text) # 质量指标(JSON格式) cost_analysis = Column(Text) # 成本分析(JSON格式) optimization_suggestions = Column(Text) # 优化建议(JSON格式) class Alert(Base): """预警模型""" __tablename__ = "alerts" id = Column(Integer, primary_key=True) tenant_id = Column(String(50), nullable=False, default=DEFAULT_TENANT, index=True) rule_name = Column(String(100), nullable=False) alert_type = Column(String(50), nullable=False) level = Column(String(20), nullable=False) # info, warning, error, critical severity = Column(String(20), nullable=False, default="medium") # low, medium, high, critical message = Column(Text, nullable=False) data = Column(Text) # JSON格式的预警数据 is_active = Column(Boolean, default=True) created_at = Column(DateTime, default=datetime.now) resolved_at = Column(DateTime) 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) human_resolution = Column(Text) ai_similarity = Column(Float) approved = Column(Boolean, default=False) 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") class User(Base): """用户模型""" __tablename__ = "users" id = Column(Integer, primary_key=True) tenant_id = Column(String(50), nullable=False, default=DEFAULT_TENANT, index=True) username = Column(String(50), unique=True, nullable=False) password_hash = Column(String(128), nullable=False) email = Column(String(120), unique=True, nullable=True) name = Column(String(100), nullable=True) role = Column(String(20), default='user') # admin, user, operator is_active = Column(Boolean, default=True) created_at = Column(DateTime, default=datetime.now) last_login = Column(DateTime) def set_password(self, password): """设置密码哈希""" self.password_hash = hashlib.sha256(password.encode()).hexdigest() def check_password(self, password): """验证密码""" return self.password_hash == hashlib.sha256(password.encode()).hexdigest() def to_dict(self): """转换为字典格式(用于API响应)""" return { 'id': self.id, 'username': self.username, 'email': self.email, 'name': self.name, 'role': self.role, 'is_active': self.is_active, 'created_at': self.created_at.isoformat() if self.created_at else None, 'last_login': self.last_login.isoformat() if self.last_login else None }