from datetime import datetime from sqlalchemy import select from sqlalchemy.orm import Session from app.models import JobTitle, Permission, Role, User DEFAULT_ROLES = { "employee": "普通员工", "admin": "业务管理员", "system_admin": "系统管理员", } # 业务职级预设。用户在个人资料里选的头衔。跟制度里的分组名不一定字面一致, # 字面不一致时必须在 JOB_TITLE_GROUP_ALIASES 里加映射,否则 chat.py 拿 job_title # 做子串匹配会全部落空,LLM 反问澄清。 DEFAULT_JOB_TITLES: list[str] = [ "董事长", "总经理", "领导班子副职", "总助级", "中层干部正职及相当职级人员", "中层干部副职及相当职级人员", "教授级高工及相当职称人员", "普通员工", ] # 业务职级 -> 制度里"按职级分组"分组名的关键词列表。 # 制度里分组常写作"总院领导班子正职"这种复合词,用户选的却是"董事长"这种具体头衔, # chat.py 会拿这里的关键词代替原 job_title 做子串规则("包含任一关键词")。 # 未在此表的 job_title 回退成拿它本身做子串匹配(老行为)。 # 加/改字典项时,同步维护此表;关键词要够特异,避免误命中相邻分组 # (例如"正职"太泛,会同时命中"领导班子正职"和"中层正职")。 JOB_TITLE_GROUP_ALIASES: dict[str, list[str]] = { "董事长": ["领导班子正职"], "总经理": ["领导班子正职"], "领导班子副职": ["领导班子副职"], "总助级": ["总助级"], "中层干部正职及相当职级人员": ["中层正职", "中层干部正职"], "中层干部副职及相当职级人员": ["中层副职", "中层干部副职"], "教授级高工及相当职称人员": ["教授级高工"], "普通员工": ["普通员工"], } # 页面级权限:code -> (显示名, 模块) DEFAULT_PAGE_PERMISSIONS: dict[str, tuple[str, str]] = { "page.chat": ("智能问答", "page"), "page.documents": ("知识文档", "page"), "page.audit": ("问答审计", "page"), "page.analytics": ("数据分析", "page"), "page.settings": ("系统设置", "page"), } # 角色 -> 页面权限 code 列表 DEFAULT_ROLE_PAGE_PERMISSIONS: dict[str, list[str]] = { "employee": ["page.chat"], "admin": ["page.chat", "page.documents", "page.audit", "page.analytics"], "system_admin": list(DEFAULT_PAGE_PERMISSIONS.keys()), } def _ensure_page_permissions(db: Session) -> dict[str, Permission]: existing = {p.code: p for p in db.scalars(select(Permission)).all()} for code, (name, module) in DEFAULT_PAGE_PERMISSIONS.items(): if code not in existing: p = Permission(code=code, name=name, module=module) db.add(p) existing[code] = p db.flush() return existing def ensure_roles(db: Session) -> None: perms = _ensure_page_permissions(db) existing_roles = {role.code: role for role in db.scalars(select(Role)).all()} for code, name in DEFAULT_ROLES.items(): role = existing_roles.get(code) if role is None: role = Role(code=code, name=name) db.add(role) existing_roles[code] = role db.flush() # 只补齐默认页面权限,不覆盖管理员后续在后台自定义的权限 for code, page_codes in DEFAULT_ROLE_PAGE_PERMISSIONS.items(): role = existing_roles.get(code) if role is None: continue current = {p.code for p in role.permissions} for page_code in page_codes: if page_code not in current and page_code in perms: role.permissions.append(perms[page_code]) db.flush() def ensure_job_titles(db: Session) -> None: """把 DEFAULT_JOB_TITLES 里没入库的补进去;已存在的保留,不覆盖启用状态/顺序。""" existing = {jt.name for jt in db.scalars(select(JobTitle)).all()} for idx, name in enumerate(DEFAULT_JOB_TITLES): if name in existing: continue db.add(JobTitle(name=name, sort_order=idx, is_active=True)) db.flush() def ensure_default_admin(db: Session) -> User: ensure_roles(db) ensure_job_titles(db) user = db.scalar(select(User).where(User.phone == "13800000000")) if user: return user role = db.scalar(select(Role).where(Role.code == "system_admin")) user = User(phone="13800000000", name="系统管理员", is_superuser=True) if role: user.roles.append(role) db.add(user) db.flush() return user def get_or_create_login_user(db: Session, phone: str) -> User: ensure_roles(db) user = db.scalar(select(User).where(User.phone == phone)) if user: user.last_login_at = datetime.utcnow() return user role = db.scalar(select(Role).where(Role.code == "employee")) user = User(phone=phone, name=f"用户{phone[-4:]}", status="active", last_login_at=datetime.utcnow()) if role: user.roles.append(role) db.add(user) db.flush() return user def apply_roles(db: Session, user: User, role_codes: list[str]) -> None: ensure_roles(db) roles = db.scalars(select(Role).where(Role.code.in_(role_codes))).all() if role_codes else [] user.roles = list(roles)