PayrollManagementSystem/backend/app/schemas/role.py
liuwenxin c83287819a feat(system): 完成后端系统管理(审计/角色/操作日志/日志查询)
- 操作日志审计机制:audit 上下文(成功与失败都记、独立提交、操作人标量
  固化、commit 后查询前置约定),用户/角色全部写操作接入;request_data
  按键名的结构化脱敏 + UTF-8 字节边界截断
- 角色管理:CRUD 与启停;admin 禁删禁停、有绑定禁删(FOR UPDATE 锁行)、
  编码创建后不可改、停用角色不可再分配
- 日志查询:操作/登录两端点,列表与详情两段式(详情含已脱敏请求参数);
  时间参数统一转本地 naive(修混用时区 500 与偏移丢弃)
- 用户管理:补齐 reset_password 操作人、编辑空串归一 NULL、并发唯一键兜底 400
- 测试 301 例全绿(单元 223 / 集成 78)

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-10-10 16:28:04 +08:00

81 lines
2.8 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""角色管理的请求/响应模型。
`RoleOut` 原位于 `schemas/user.py`,因角色管理成为独立模块而迁入本文件 ——
用户表单的角色下拉与角色管理列表共用同一响应模型。
"""
import re
from pydantic import BaseModel, ConfigDict, Field, field_validator
from app.core.response import PageQuery
# 角色编码规则:小写字母开头,后接小写字母/数字/下划线,长度 2–32(与列宽一致)。
# 不允许大写与中文 —— 编码会出现在授权判断(`ROLE_ADMIN` 常量按编码比对)与
# 操作日志里,保持单一风格避免大小写/全角混用造成对照困难
ROLE_CODE_PATTERN = re.compile(r"^[a-z][a-z0-9_]{1,31}$")
class RoleOut(BaseModel):
"""角色基础响应(用户表单下拉与角色列表共用)。"""
model_config = ConfigDict(from_attributes=True)
id: int
role_code: str
role_name: str
description: str | None = None
sort_order: int = 0
status: int = 1
class RoleManageOut(RoleOut):
"""角色管理列表项:额外携带绑定用户数,供前端提示删除保护的原因。"""
user_count: int = 0
class RoleCreateIn(BaseModel):
"""新增角色。"""
model_config = ConfigDict(str_strip_whitespace=True)
role_code: str = Field(min_length=2, max_length=32, description="角色编码,创建后不可修改")
role_name: str = Field(min_length=1, max_length=64, description="角色名称")
description: str | None = Field(default=None, max_length=255)
sort_order: int = Field(default=0, ge=0, description="显示排序,越小越靠前")
@field_validator("role_code")
@classmethod
def _check_code(cls, value: str) -> str:
if not ROLE_CODE_PATTERN.match(value):
raise ValueError("角色编码须以小写字母开头,仅可含小写字母、数字与下划线")
return value
class RoleUpdateIn(BaseModel):
"""编辑角色。
**不含 role_code** —— 编码是授权判定的锚点,修改会让既有授权语义静默改变。
前端表单全量提交,故为全量替换语义。
"""
model_config = ConfigDict(str_strip_whitespace=True)
role_name: str = Field(min_length=1, max_length=64, description="角色名称")
description: str | None = Field(default=None, max_length=255)
sort_order: int = Field(default=0, ge=0, description="显示排序,越小越靠前")
class RoleStatusIn(BaseModel):
"""启用/禁用角色。"""
status: int = Field(ge=0, le=1, description="1启用 0禁用")
class RoleQuery(PageQuery):
"""角色列表查询条件。"""
keyword: str | None = Field(default=None, max_length=64, description="编码或名称,模糊匹配")
status: int | None = Field(default=None, ge=0, le=1, description="状态筛选")