feat(system): 业务岗位角色管理接口与保护规则
- 四层实现:仓储(FOR UPDATE 锁行 + 引用计数钩子预留)/ schemas / service / api 共 7 个端点 - 保护规则:内置岗位禁删禁停、编码创建后不可改、模板须在注册表内(未注册 400) - 写操作全走审计上下文;冒烟验证 7 项(含成功/失败双路径落日志) - 端点:列表/新增/详情/编辑/删除/启停 + meta/templates 模板下拉 Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
1 parent
1b3509b20f
commit
7a0f3f4b98
6 files changed
+590
No files matched your search
@@ -0,0 +1,122 @@
|
||||
"""业务岗位角色管理接口(需求 #28:岗位可扩展 + 绑定公式模板)。
|
||||
|
||||
保护规则(内置岗位禁删禁停、编码不可改、模板须在注册表内)见
|
||||
`business_role_service` 模块 docstring。前端会禁用相应按钮,但**后端校验是唯一防线**。
|
||||
|
||||
全部要求管理员权限;写操作经 `RequestMetaDep` 带入请求元信息由 service
|
||||
层写入操作日志。
|
||||
"""
|
||||
|
||||
from typing import Annotated
|
||||
|
||||
from fastapi import APIRouter, Path, Query
|
||||
|
||||
from app.api.deps import AdminUser, DbSession, RequestMetaDep
|
||||
from app.core.response import ApiResponse, PageResult, ok
|
||||
from app.schemas.business_role import (
|
||||
BusinessRoleCreateIn,
|
||||
BusinessRoleOut,
|
||||
BusinessRoleQuery,
|
||||
BusinessRoleStatusIn,
|
||||
BusinessRoleUpdateIn,
|
||||
TemplateOptionOut,
|
||||
)
|
||||
from app.services import business_role_service
|
||||
|
||||
router = APIRouter(prefix="/business-roles", tags=["系统管理 · 岗位角色"])
|
||||
|
||||
|
||||
@router.get("", response_model=ApiResponse[PageResult[BusinessRoleOut]], summary="岗位列表")
|
||||
def list_roles(
|
||||
session: DbSession,
|
||||
_: AdminUser,
|
||||
query: Annotated[BusinessRoleQuery, Query()],
|
||||
) -> ApiResponse[PageResult[BusinessRoleOut]]:
|
||||
"""分页查询业务岗位角色(含停用)。"""
|
||||
return ok(business_role_service.list_roles(session, query))
|
||||
|
||||
|
||||
@router.post("", response_model=ApiResponse[BusinessRoleOut], summary="新增岗位")
|
||||
def create_role(
|
||||
session: DbSession,
|
||||
current_user: AdminUser,
|
||||
payload: BusinessRoleCreateIn,
|
||||
meta: RequestMetaDep,
|
||||
) -> ApiResponse[BusinessRoleOut]:
|
||||
"""新增岗位。编码全局唯一、创建后不可修改;模板须在注册表内;新岗位默认启用。"""
|
||||
return ok(
|
||||
business_role_service.create_role(session, payload, operator=current_user, meta=meta),
|
||||
message="岗位已创建",
|
||||
)
|
||||
|
||||
|
||||
@router.get(
|
||||
"/meta/templates",
|
||||
response_model=ApiResponse[list[TemplateOptionOut]],
|
||||
summary="公式模板下拉",
|
||||
)
|
||||
def list_template_options(session: DbSession, _: AdminUser) -> ApiResponse[list[TemplateOptionOut]]:
|
||||
"""取公式模板下拉(含声明参数,供岗位表单展示)。
|
||||
|
||||
定义在 `/{role_id}` 之前:静态路径优先,避免 "meta" 被当作路径参数解析。
|
||||
"""
|
||||
return ok(business_role_service.list_template_options())
|
||||
|
||||
|
||||
@router.get("/{role_id}", response_model=ApiResponse[BusinessRoleOut], summary="岗位详情")
|
||||
def get_role(
|
||||
session: DbSession,
|
||||
_: AdminUser,
|
||||
role_id: Annotated[int, Path(ge=1)],
|
||||
) -> ApiResponse[BusinessRoleOut]:
|
||||
"""按主键查询岗位详情。"""
|
||||
return ok(business_role_service.get_role(session, role_id))
|
||||
|
||||
|
||||
@router.put("/{role_id}", response_model=ApiResponse[BusinessRoleOut], summary="编辑岗位")
|
||||
def update_role(
|
||||
session: DbSession,
|
||||
current_user: AdminUser,
|
||||
role_id: Annotated[int, Path(ge=1)],
|
||||
payload: BusinessRoleUpdateIn,
|
||||
meta: RequestMetaDep,
|
||||
) -> ApiResponse[BusinessRoleOut]:
|
||||
"""编辑岗位名称/模板/说明/排序。
|
||||
|
||||
**不含 role_code** —— 编码是参数维度值与模板绑定的锚点。
|
||||
"""
|
||||
return ok(
|
||||
business_role_service.update_role(
|
||||
session, role_id, payload, operator=current_user, meta=meta
|
||||
),
|
||||
message="已保存",
|
||||
)
|
||||
|
||||
|
||||
@router.put(
|
||||
"/{role_id}/status", response_model=ApiResponse[BusinessRoleOut], summary="启用/禁用岗位"
|
||||
)
|
||||
def set_status(
|
||||
session: DbSession,
|
||||
current_user: AdminUser,
|
||||
role_id: Annotated[int, Path(ge=1)],
|
||||
payload: BusinessRoleStatusIn,
|
||||
meta: RequestMetaDep,
|
||||
) -> ApiResponse[BusinessRoleOut]:
|
||||
"""启用或禁用岗位。内置岗位不可停用。"""
|
||||
result = business_role_service.set_status(
|
||||
session, role_id, payload.status, operator=current_user, meta=meta
|
||||
)
|
||||
return ok(result, message="已启用" if payload.status == 1 else "已禁用")
|
||||
|
||||
|
||||
@router.delete("/{role_id}", response_model=ApiResponse[None], summary="删除岗位")
|
||||
def delete_role(
|
||||
session: DbSession,
|
||||
current_user: AdminUser,
|
||||
role_id: Annotated[int, Path(ge=1)],
|
||||
meta: RequestMetaDep,
|
||||
) -> ApiResponse[None]:
|
||||
"""删除岗位。内置岗位不可删除;有人员引用的岗位不可删除。"""
|
||||
business_role_service.delete_role(session, role_id, operator=current_user, meta=meta)
|
||||
return ok(message="岗位已删除")
|
||||
Reference in new issue
Block a user