Skip to content

部门/职级/岗位

部门、职级、岗位是组织架构管理的三个核心模块。部门采用树形结构,职级和岗位为简单 CRUD 模块,均继承 BaseService。用户表通过 dept_id、position_id、level_id 三个外键关联这三个模块。

部门管理 ​

部门模型 ​

python
# src/modules/system/dept/models.py
# ============================================================
# 部门模型
# ============================================================
class Dept(BaseModel, BaseDB):
    """部门模型类"""
    # ============================================================
    # 表名配置
    # ============================================================
    __tablename__ = DB_PREFIX + "dept"
    __table_comment__ = "部门表"

    # ============================================================
    # 字段定义
    # ============================================================
    # 部门名称
    name = Column(String(150), nullable=False, index=True, comment="部门名称")
    # 部门类型:1-公司 2-子公司 3-部门 4-小组
    type = Column(Integer, default=0, server_default=text('0'), comment="部门类型:1-公司 2-子公司 3-部门 4-小组")
    # 上级部门ID
    parent_id = Column(Integer, default=0, server_default=text('0'), index=True, comment="上级部门ID")
    # 部门排序
    sort = Column(Integer, default=0, server_default=text('0'), comment="部门排序")
    # 备注
    note = Column(String(255), nullable=True, comment="备注")

    # ============================================================
    # 内置方法
    # ============================================================
    def __str__(self):
        """返回部门名称作为字符串表示"""
        return '部门{}'.format(self.name)

树形结构 ​

部门通过 parent_id 字段形成树形结构,与菜单类似:

公司总部 (parent_id=0)
├── 技术部 (parent_id=1)
│ ├── 前端组 (parent_id=2)
│ └── 后端组 (parent_id=2)
└── 市场部 (parent_id=1)

删除前校验 ​

部门删除时需检查是否存在下级部门或用户引用,避免组织架构悬空:

python
# src/modules/system/dept/service.py
from src.common.base_service import BaseService
from src.core.exceptions import BizError
from src.modules.system.dept.repository import DeptRepository
from src.modules.system.user.repository import UserRepository


class DeptService(BaseService):
    """部门服务类"""
    repository = DeptRepository
    form = DeptForm
    model_name = "部门"

    @classmethod
    def before_delete(cls, ids):
        """
        删除前校验:检查下级部门和用户引用

        Args:
            ids: 待删除的部门ID列表

        Raises:
            BizError: 存在下级部门或用户引用时抛出
        """
        for did in ids:
            # 检查是否存在下级部门
            if DeptRepository.count_children(did) > 0:
                raise BizError(f"部门ID {did} 存在下级部门,请先删除下级部门")
            # 检查是否存在用户引用
            if UserRepository.count_by({'dept_id': did}) > 0:
                raise BizError(f"部门ID {did} 已被用户引用,请先调整用户部门")

职级管理 ​

职级模型 ​

python
# src/modules/system/level/models.py
# ============================================================
# 职级模型
# ============================================================
class Level(BaseModel, BaseDB):
    """职级模型类"""
    # ============================================================
    # 表名配置
    # ============================================================
    __tablename__ = DB_PREFIX + "level"
    __table_comment__ = "职级表"

    # ============================================================
    # 字段定义
    # ============================================================
    # 职级名称
    name = Column(String(255), nullable=False, index=True, comment="职级名称")
    # 职级状态:1-在用 2-停用
    status = Column(Integer, default=0, server_default=text('0'), index=True, comment="职级状态:1-在用 2-停用")
    # 职级排序
    sort = Column(Integer, default=0, server_default=text('0'), comment="职级排序")

    # ============================================================
    # 内置方法
    # ============================================================
    def __repr__(self):
        """返回职级名称作为字符串表示"""
        return '职级:{}'.format(self.name)

表单验证 ​

python
# src/modules/system/level/schema.py
from wtforms import StringField, IntegerField
from wtforms.validators import DataRequired, Length, NumberRange, Optional
from src.common.forms.base_form import BaseForm
from src.modules.system.level.repository import LevelRepository


class LevelForm(BaseForm):
    """职级创建/编辑表单"""
    name = StringField('职级名称', validators=[
        DataRequired(message='职级名称不能为空'),
        Length(max=150, message='职级名称长度不得超过150个字符')
    ])
    status = IntegerField('职级状态', validators=[
        DataRequired(message='职级状态不能为空'),
        NumberRange(min=1, max=2, message='职级状态值在1~2之间')
    ])
    sort = IntegerField('职级排序', validators=[
        Optional(),
        NumberRange(min=0, max=99999, message='职级排序值在0~99999之间')
    ])

    def validate_name(self, field):
        """职级名称唯一性校验"""
        if not field.data:
            return
        current_id = self.id.data if self.id.data else None
        if LevelRepository.exists_by({'name': field.data}, exclude_id=current_id):
            raise ValidationError("职级名称已存在")


class LevelStatusForm(BaseForm):
    """职级状态更新表单"""
    id = IntegerField('职级ID', validators=[
        DataRequired(message='职级ID不能为空'),
        NumberRange(min=1, message='职级ID必须大于0')
    ])
    status = IntegerField('职级状态', validators=[
        DataRequired(message='职级状态不能为空'),
        NumberRange(min=1, max=2, message='职级状态值在1~2之间')
    ])

业务服务 ​

职级模块继承 BaseService,声明差异点即可获得完整 CRUD 能力。删除前校验用户引用,支持 Excel 导入导出:

python
# src/modules/system/level/service.py
from src.common.base_service import BaseService
from src.core.exceptions import BizError
from src.modules.system.level.schema import LevelForm, LevelStatusForm
from src.modules.system.level.repository import LevelRepository
from src.modules.system.user.repository import UserRepository


class LevelService(BaseService):
    """职级服务类,继承 BaseService 获得标准 CRUD 能力"""
    repository = LevelRepository
    form = LevelForm
    status_form = LevelStatusForm
    model_name = "职级"

    @classmethod
    def before_delete(cls, ids):
        """删除前校验:存在用户引用该职级时禁止删除"""
        for lid in ids:
            if UserRepository.count_by({'level_id': lid}) > 0:
                raise BizError(f"职级ID {lid} 已被用户引用,无法删除")


# 模块级代理函数
get_level_page = LevelService.get_page
get_level_detail = LevelService.get_detail
add_level = LevelService.add
update_level = LevelService.update
delete_levels = LevelService.remove
update_level_status = LevelService.update_status
get_level_list = LevelService.get_list

岗位管理 ​

岗位模型 ​

python
# src/modules/system/position/models.py
# ============================================================
# 岗位模型
# ============================================================
class Position(BaseModel, BaseDB):
    """岗位模型类"""
    # ============================================================
    # 表名配置
    # ============================================================
    __tablename__ = DB_PREFIX + "position"
    __table_comment__ = "岗位表"

    # ============================================================
    # 字段定义
    # ============================================================
    # 岗位名称
    name = Column(String(255), nullable=False, index=True, comment="岗位名称")
    # 岗位状态:1-在用 2-停用
    status = Column(Integer, default=0, server_default=text('0'), index=True, comment="岗位状态:1-在用 2-停用")
    # 岗位排序
    sort = Column(Integer, default=0, server_default=text('0'), comment="岗位排序")

    # ============================================================
    # 内置方法
    # ============================================================
    def __repr__(self):
        """返回岗位名称作为字符串表示"""
        return '岗位:{}'.format(self.name)

表单验证 ​

python
# src/modules/system/position/schema.py
from wtforms import StringField, IntegerField
from wtforms.validators import DataRequired, Length, NumberRange, Optional
from src.common.forms.base_form import BaseForm
from src.modules.system.position.repository import PositionRepository


class PositionForm(BaseForm):
    """岗位创建/编辑表单"""
    name = StringField('岗位名称', validators=[
        DataRequired(message='岗位名称不能为空'),
        Length(max=150, message='岗位名称长度不得超过150个字符')
    ])
    status = IntegerField('岗位状态', validators=[
        DataRequired(message='岗位状态不能为空'),
        NumberRange(min=1, max=2, message='岗位状态值在1~2之间')
    ])
    sort = IntegerField('岗位排序', validators=[
        Optional(),
        NumberRange(min=0, max=99999, message='岗位排序值在0~99999之间')
    ])

    def validate_name(self, field):
        """岗位名称唯一性校验"""
        if not field.data:
            return
        current_id = self.id.data if self.id.data else None
        if PositionRepository.exists_by({'name': field.data}, exclude_id=current_id):
            raise ValidationError("岗位名称已存在")


class PositionStatusForm(BaseForm):
    """岗位状态更新表单"""
    id = IntegerField('岗位ID', validators=[
        DataRequired(message='岗位ID不能为空'),
        NumberRange(min=1, message='岗位ID必须大于0')
    ])
    status = IntegerField('岗位状态', validators=[
        DataRequired(message='岗位状态不能为空'),
        NumberRange(min=1, max=2, message='岗位状态值在1~2之间')
    ])

数据访问层 ​

python
# src/modules/system/position/repository.py
from src.common.base_repository import BaseRepository
from src.common.constants.common import PAGE_SIZE
from src.modules.system.position.models import Position


class PositionRepository(BaseRepository):
    """岗位数据仓储,继承 BaseRepository 获得通用 CRUD 能力"""
    model = Position

    @classmethod
    def page(cls, params: dict):
        """分页查询"""
        return cls.find_page(
            page=int(params.get('pageNo', 1)),
            page_size=int(params.get('pageSize', PAGE_SIZE)),
            filters={'status': params.get('status')},
            like_filters={'name': params.get('name')},
            order_by='sort',
        )

    @classmethod
    def list_enabled(cls, params=None):
        """查询启用的岗位列表"""
        params = params or {}
        return cls.find_list(
            filters={'status': 1},
            like_filters={'name': params.get('name')},
            order_by='sort',
        )

业务服务 ​

python
# src/modules/system/position/service.py
from src.common.base_service import BaseService
from src.core.exceptions import BizError
from src.modules.system.position.schema import PositionForm, PositionStatusForm
from src.modules.system.position.repository import PositionRepository
from src.modules.system.user.repository import UserRepository


class PositionService(BaseService):
    """岗位服务类,继承 BaseService 获得标准 CRUD 能力"""
    repository = PositionRepository
    form = PositionForm
    status_form = PositionStatusForm
    model_name = "岗位"

    @classmethod
    def before_delete(cls, ids):
        """删除前校验:存在用户引用该岗位时禁止删除"""
        for pid in ids:
            if UserRepository.count_by({'position_id': pid}) > 0:
                raise BizError(f"岗位ID {pid} 已被用户引用,无法删除")


# 模块级代理函数
get_position_page = PositionService.get_page
get_position_detail = PositionService.get_detail
add_position = PositionService.add
update_position = PositionService.update
delete_positions = PositionService.remove
update_position_status = PositionService.update_status
get_position_list = PositionService.get_list

通用 CRUD 接口 ​

职级和岗位模块继承 BaseService,自动生成标准接口:

接口方法权限节点说明
/api/v1/level/pageGETsys:level:page职级分页列表
/api/v1/level/listGETsys:level:list职级列表(无分页)
/api/v1/level/detail/{id}GETsys:level:detail职级详情
/api/v1/level/addPOSTsys:level:add新增职级
/api/v1/level/updatePUTsys:level:update编辑职级
/api/v1/level/delete/{id}DELETEsys:level:delete删除职级
/api/v1/level/batchDeleteDELETEsys:level:batchDelete批量删除
/api/v1/level/statusPUTsys:level:status设置状态
/api/v1/level/importPOSTsys:level:import导入 Excel
/api/v1/level/exportGETsys:level:export导出 Excel
/api/v1/position/pageGETsys:position:page岗位分页列表
/api/v1/position/listGETsys:position:list岗位列表(无分页)
/api/v1/position/detail/{id}GETsys:position:detail岗位详情
/api/v1/position/addPOSTsys:position:add新增岗位
/api/v1/position/updatePUTsys:position:update编辑岗位
/api/v1/position/delete/{id}DELETEsys:position:delete删除岗位
/api/v1/position/batchDeleteDELETEsys:position:batchDelete批量删除
/api/v1/position/statusPUTsys:position:status设置状态

Excel 导入导出

职级模块支持 Excel 导入导出(import_level / export_level),导入时逐行校验并返回成功/失败条数。岗位模块结构相同,可按需添加导入导出功能。

总结 ​

组织架构模块具备以下特点:

1. 部门树形:parent_id 形成多级部门结构,删除前校验下级部门和用户引用
2. 职级/岗位:简单 CRUD,继承 BaseService,声明差异点即可
3. 表单验证:WTForms Field 约束(DataRequired/Length/NumberRange)
4. 数据仓库:BaseRepository 提供通用 CRUD 能力,模块级代理函数
5. 用户关联:用户表通过 dept_id、position_id、level_id 关联
6. 删除保护:before_delete 钩子防止引用悬空

小蚂蚁云团队 · 提供技术支持