# ============================================================================= # 企微IT智能服务台 — 业务联系人模型 # ============================================================================= # 说明:对应数据库 business_contacts 表,存储非IT业务部门联系人信息 # 当员工提出的问题不属于IT服务台服务范围时,系统通过 Dify 意图识别 # 判定业务类别,从本表查询对应联系人,推送名片卡片到聊天中。 # 员工点击「联系TA」可跳转企微单聊(openEnterpriseChat)。 # # 业务类别(business_category)取值: # 行政 / 人力资源 / 财务 / 法务 / 行政-物业 # ============================================================================= from datetime import datetime from sqlalchemy import Boolean, DateTime, Index, Integer, String from sqlalchemy.orm import Mapped, mapped_column from app.database import Base class BusinessContact(Base): """业务联系人模型 — 对应 business_contacts 表。 存储非IT业务部门联系人信息,用于路由推荐功能。 当 Dify 判定消息为非IT业务路由时,按 business_category 查询本表, 取第一条 is_active=True 的联系人,推送名片卡片。 Attributes: id: 主键,自增 name: 联系人姓名 gender: 性别(male/female) department: 部门名称(如「行政部」) position: 岗位(如「设备管理岗」) responsibility: 负责业务描述(如「打印机/复印机/扫描仪」) extension: 分机号 service_area: 服务区域/办公地点 wecom_userid: 企微用户ID(用于 openEnterpriseChat 调用) avatar_url: 头像URL(为空时用姓名首字渲染) business_category: 业务类别(行政/人力资源/财务/法务/行政-物业) is_active: 是否启用 created_at: 创建时间 updated_at: 更新时间 """ __tablename__ = "business_contacts" # 主键:自增整数 id: Mapped[int] = mapped_column( Integer, primary_key=True, autoincrement=True, comment="主键", ) # 联系人姓名 name: Mapped[str] = mapped_column( String(50), nullable=False, comment="联系人姓名", ) # 性别(male/female) gender: Mapped[str] = mapped_column( String(10), nullable=False, default="male", comment="性别(male/female)", ) # 部门名称 department: Mapped[str] = mapped_column( String(100), nullable=False, comment="部门名称", ) # 岗位 position: Mapped[str] = mapped_column( String(100), nullable=False, comment="岗位", ) # 负责业务描述 responsibility: Mapped[str] = mapped_column( String(500), nullable=False, comment="负责业务描述", ) # 分机号 extension: Mapped[str | None] = mapped_column( String(20), nullable=True, default=None, comment="分机号", ) # 服务区域/办公地点 service_area: Mapped[str | None] = mapped_column( String(200), nullable=True, default=None, comment="服务区域/办公地点", ) # 企微用户ID(用于 wx.invoke('openEnterpriseChat', {userids: '...'}) 调用) wecom_userid: Mapped[str] = mapped_column( String(100), nullable=False, comment="企微用户ID", ) # 头像URL(为空时前端用姓名首字渐变色块渲染) avatar_url: Mapped[str | None] = mapped_column( String(500), nullable=True, default=None, comment="头像URL(为空用姓名首字渲染)", ) # 业务类别(与 Dify 输出的 business_category 对应) # 取值:行政 / 人力资源 / 财务 / 法务 / 行政-物业 business_category: Mapped[str] = mapped_column( String(50), nullable=False, comment="业务类别(行政/人力资源/财务/法务/行政-物业)", ) # 是否启用 is_active: Mapped[bool] = mapped_column( Boolean, nullable=False, default=True, comment="是否启用", ) # 创建时间 created_at: Mapped[datetime] = mapped_column( DateTime(timezone=True), nullable=False, default=datetime.now, comment="创建时间", ) # 更新时间 updated_at: Mapped[datetime] = mapped_column( DateTime(timezone=True), nullable=False, default=datetime.now, onupdate=datetime.now, comment="更新时间", ) # 索引定义 __table_args__ = ( # 按业务类别 + 是否启用查询(路由推荐时使用) Index("idx_business_contacts_category", "business_category", "is_active"), ) def to_dict(self) -> dict: """将联系人信息转为字典(用于 extra_data 透传给前端)。 Returns: dict: 联系人完整信息 """ return { "id": self.id, "name": self.name, "gender": self.gender, "department": self.department, "position": self.position, "responsibility": self.responsibility, "extension": self.extension or "", "service_area": self.service_area or "", "wecom_userid": self.wecom_userid, "avatar_url": self.avatar_url or "", "business_category": self.business_category, } def __repr__(self) -> str: """联系人对象的字符串表示,方便调试。""" return ( f"" )