feat: 租户管理体系建设 CRUD + 各业务模块接入 tenant_id
1. 新增 Tenant 模型(tenants 表),支持租户创建、重命名、删除 2. 新增 /api/tenants CRUD 蓝图,default 租户不可删除 3. 数据库初始化时自动创建默认租户记录 4. Dashboard 新增租户管理标签页(创建/编辑/删除租户) 5. 各业务模块写入数据时正确传递 tenant_id: - realtime_chat: create_session 和 _save_conversation 支持 tenant_id - dialogue_manager: _save_conversation 和 create_work_order 支持 tenant_id - conversation_history: save_conversation 支持 tenant_id - workorder_sync: sync_from_feishu 支持 tenant_id - websocket_server: create_session 传递 tenant_id - HTTP chat API: create_session 传递 tenant_id - feishu_sync API: 同步时传递 tenant_id - workorders API: 创建工单时传递 tenant_id 6. 网页对话入口添加租户选择器 7. 知识库搜索按租户隔离(realtime_chat 中 _search_knowledge 传递 tenant_id) 8. 初始化时自动加载租户列表填充选择器
This commit is contained in:
@@ -68,10 +68,35 @@ class DatabaseManager:
|
||||
Base.metadata.create_all(bind=self.engine)
|
||||
logger.info("数据库初始化成功")
|
||||
|
||||
# 确保默认租户存在
|
||||
self._ensure_default_tenant()
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"数据库初始化失败: {e}")
|
||||
raise
|
||||
|
||||
def _ensure_default_tenant(self):
|
||||
"""确保默认租户记录存在"""
|
||||
try:
|
||||
from .models import Tenant, DEFAULT_TENANT
|
||||
session = self.SessionLocal()
|
||||
try:
|
||||
existing = session.query(Tenant).filter(Tenant.tenant_id == DEFAULT_TENANT).first()
|
||||
if not existing:
|
||||
session.add(Tenant(
|
||||
tenant_id=DEFAULT_TENANT,
|
||||
name="默认租户",
|
||||
description="系统默认租户"
|
||||
))
|
||||
session.commit()
|
||||
logger.info("默认租户已创建")
|
||||
except Exception:
|
||||
session.rollback()
|
||||
finally:
|
||||
session.close()
|
||||
except Exception as e:
|
||||
logger.warning(f"确保默认租户失败(不影响启动): {e}")
|
||||
|
||||
@contextmanager
|
||||
def get_session(self) -> Generator[Session, None, None]:
|
||||
"""获取数据库会话的上下文管理器"""
|
||||
|
||||
@@ -9,6 +9,35 @@ 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"
|
||||
|
||||
Reference in New Issue
Block a user