签入版本
This commit is contained in:
@@ -0,0 +1,287 @@
|
||||
# Router 层(Flask Blueprint)
|
||||
|
||||
Router 层是 HTTP 接口层,负责定义路由、权限装饰器和请求参数解析。每个业务模块对应一个 router 文件,所有业务逻辑委托给 Service 层处理。
|
||||
|
||||
## 文件位置
|
||||
|
||||
```
|
||||
src/modules/system/position/router.py
|
||||
```
|
||||
|
||||
## 完整代码
|
||||
|
||||
以岗位模块为例,`src/modules/system/position/router.py` 完整内容:
|
||||
|
||||
```python
|
||||
"""
|
||||
岗位管理控制器模块
|
||||
=============================================================
|
||||
|
||||
提供岗位(Position)相关的API接口,包括:
|
||||
- 岗位分页查询
|
||||
- 岗位详情查询
|
||||
- 岗位添加、更新、删除
|
||||
- 岗位状态设置
|
||||
- 岗位数据列表获取
|
||||
"""
|
||||
from flask import Blueprint, request
|
||||
|
||||
from src.middleware import check_demo, operation_log
|
||||
from src.core.permission import check_permission
|
||||
from src.modules.system.position import service as position
|
||||
from src.common.utils.request import parse_batch_ids, parse_request_body
|
||||
|
||||
from src.core import response as R
|
||||
|
||||
position_blue = Blueprint('position', __name__, url_prefix='/position')
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 岗位分页查询
|
||||
# ============================================================
|
||||
|
||||
@position_blue.route('/page', methods=["GET"])
|
||||
@check_permission("sys:position:page")
|
||||
@operation_log("岗位管理", "查询")
|
||||
def page():
|
||||
"""
|
||||
查询岗位分页数据
|
||||
|
||||
Returns:
|
||||
JSON: 岗位分页数据,包含 records(数据列表)、total(总记录数)等
|
||||
"""
|
||||
return R.ok(data=position.get_position_page(request.args))
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 岗位详情查询
|
||||
# ============================================================
|
||||
|
||||
@position_blue.route('/detail/<int:id>', methods=["GET"])
|
||||
@check_permission("sys:position:detail")
|
||||
@operation_log("岗位管理", "详情")
|
||||
def detail(id):
|
||||
"""
|
||||
查询岗位详情
|
||||
|
||||
Args:
|
||||
id: 岗位ID
|
||||
|
||||
Returns:
|
||||
JSON: 岗位详细信息
|
||||
"""
|
||||
data = position.get_position_detail(id)
|
||||
return R.ok(data=data)
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 岗位添加
|
||||
# ============================================================
|
||||
|
||||
@position_blue.route('/add', methods=["POST"])
|
||||
@check_permission("sys:position:add")
|
||||
@check_demo
|
||||
@operation_log("岗位管理", "新增")
|
||||
def add():
|
||||
"""
|
||||
添加岗位
|
||||
|
||||
Returns:
|
||||
JSON: 操作结果
|
||||
"""
|
||||
json_data, err = parse_request_body()
|
||||
if err:
|
||||
return R.failed(msg=err)
|
||||
position.add_position(json_data)
|
||||
return R.ok(msg="添加成功")
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 岗位更新
|
||||
# ============================================================
|
||||
|
||||
@position_blue.route('/update', methods=["PUT"])
|
||||
@check_permission("sys:position:update")
|
||||
@check_demo
|
||||
@operation_log("岗位管理", "修改")
|
||||
def update():
|
||||
"""
|
||||
更新岗位
|
||||
|
||||
Returns:
|
||||
JSON: 操作结果
|
||||
"""
|
||||
json_data, err = parse_request_body()
|
||||
if err:
|
||||
return R.failed(msg=err)
|
||||
position.update_position(json_data)
|
||||
return R.ok(msg="更新成功")
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 岗位删除
|
||||
# ============================================================
|
||||
|
||||
@position_blue.route('/delete/<string:id>', methods=["DELETE"])
|
||||
@check_permission("sys:position:delete")
|
||||
@check_demo
|
||||
@operation_log("岗位管理", "删除")
|
||||
def delete(id):
|
||||
"""
|
||||
删除岗位
|
||||
|
||||
Args:
|
||||
id: 岗位ID(支持逗号分隔的多个ID)
|
||||
|
||||
Returns:
|
||||
JSON: 操作结果
|
||||
"""
|
||||
count = position.delete_positions(id)
|
||||
return R.ok(msg=f"本次共删除{count}条数据")
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 岗位批量删除
|
||||
# ============================================================
|
||||
|
||||
@position_blue.route('/batchDelete', methods=["DELETE"])
|
||||
@check_permission("sys:position:batchDelete")
|
||||
@check_demo
|
||||
@operation_log("岗位管理", "批量删除")
|
||||
def batch_delete():
|
||||
"""
|
||||
批量删除岗位
|
||||
|
||||
Request Body:
|
||||
[1, 2, 3] # 岗位ID数组
|
||||
|
||||
Returns:
|
||||
JSON: 操作结果
|
||||
"""
|
||||
id_str, err = parse_batch_ids()
|
||||
if err:
|
||||
return err
|
||||
count = position.delete_positions(id_str)
|
||||
return R.ok(msg=f"本次共删除{count}条数据")
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 岗位状态设置
|
||||
# ============================================================
|
||||
|
||||
@position_blue.route('/status', methods=["PUT"])
|
||||
@check_permission("sys:position:status")
|
||||
@check_demo
|
||||
@operation_log("岗位管理", "状态变更")
|
||||
def status():
|
||||
"""
|
||||
设置岗位状态
|
||||
|
||||
Returns:
|
||||
JSON: 操作结果
|
||||
"""
|
||||
json_data, err = parse_request_body()
|
||||
if err:
|
||||
return R.failed(msg=err)
|
||||
position.update_position_status(json_data)
|
||||
return R.ok(msg="设置成功")
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 岗位列表获取(无分页)
|
||||
# ============================================================
|
||||
|
||||
@position_blue.route('/list', methods=["GET"])
|
||||
@check_permission("sys:position:list")
|
||||
@operation_log("岗位管理", "查询")
|
||||
def get_position_list():
|
||||
"""
|
||||
获取岗位数据列表(无分页)
|
||||
|
||||
用于下拉选择框,支持 name 模糊匹配。
|
||||
|
||||
Returns:
|
||||
JSON: 岗位列表数据
|
||||
"""
|
||||
result = position.get_position_list(request.args)
|
||||
return R.ok(data=result)
|
||||
```
|
||||
|
||||
## 代码解析
|
||||
|
||||
### Blueprint 实例
|
||||
|
||||
```python
|
||||
position_blue = Blueprint('position', __name__, url_prefix='/position')
|
||||
```
|
||||
|
||||
每个 router 文件创建一个独立的 `Blueprint` 实例,后续在 `src/routes/v1.py` 中统一注册。
|
||||
|
||||
### 装饰器说明
|
||||
|
||||
| 装饰器 | 作用 | 位置 |
|
||||
|:---|:---|:---|
|
||||
| `@position_blue.route()` | 定义 HTTP 方法和路径 | 最外层 |
|
||||
| `@check_permission('sys:position:page')` | RBAC 权限校验 | 路由装饰器之后 |
|
||||
| `@check_demo` | 演示模式拦截(写操作) | 权限装饰器之后 |
|
||||
| `@operation_log("岗位管理", "查询")` | 操作日志记录 | 最内层 |
|
||||
|
||||
**装饰器顺序必须严格遵守**:路由 → 权限 → 演示模式 → 操作日志。
|
||||
|
||||
### 权限字符串命名规范
|
||||
|
||||
```
|
||||
sys:{module}:{action}
|
||||
```
|
||||
|
||||
| 动作 | HTTP 方法 | 说明 |
|
||||
|:---|:---|:---|
|
||||
| `page` | GET | 分页查询 |
|
||||
| `detail` | GET | 详情查询 |
|
||||
| `list` | GET | 列表查询(无分页) |
|
||||
| `add` | POST | 新增 |
|
||||
| `update` | PUT | 更新 |
|
||||
| `delete` | DELETE | 单条删除 |
|
||||
| `batchDelete` | DELETE | 批量删除 |
|
||||
| `status` | PUT | 状态变更 |
|
||||
|
||||
### 参数解析
|
||||
|
||||
```python
|
||||
# 解析请求体 JSON(POST/PUT)
|
||||
json_data, err = parse_request_body()
|
||||
if err:
|
||||
return R.failed(msg=err)
|
||||
|
||||
# 解析批量删除的 ID 数组(DELETE)
|
||||
id_str, err = parse_batch_ids()
|
||||
if err:
|
||||
return err
|
||||
|
||||
# 获取查询参数(GET)
|
||||
params = request.args # 如 request.args.get('name')
|
||||
```
|
||||
|
||||
### 响应封装
|
||||
|
||||
```python
|
||||
# 成功响应
|
||||
R.ok(data=data) # 返回数据
|
||||
R.ok(msg="添加成功") # 返回消息
|
||||
R.ok(data=data, msg="ok") # 同时返回数据和消息
|
||||
|
||||
# 失败响应
|
||||
R.failed(msg="参数错误") # 返回错误消息
|
||||
```
|
||||
|
||||
## 开发要点
|
||||
|
||||
1. **只需两步注册**:一行导入 Blueprint,一行添加到 `BLUEPRINTS` 列表
|
||||
2. **prefix 与模块目录名保持一致**:便于代码导航
|
||||
3. **所有业务蓝图都挂在 `v1` 路由组下**:自动享受 `login_required` 认证保护
|
||||
4. **装饰器顺序**:路由 → `@check_permission` → `@check_demo` → `@operation_log`
|
||||
5. **Router 层不处理业务逻辑**:只做参数解析和响应封装,业务逻辑委托 Service 层
|
||||
|
||||
## 总结
|
||||
|
||||
Router 层通过 Flask Blueprint 定义路由,使用 `@check_permission` 实现 RBAC 权限控制,`@check_demo` 拦截演示模式写操作,`@operation_log` 自动记录操作日志。参数解析通过 `parse_request_body()` / `parse_batch_ids()` 完成,响应封装通过 `R.ok()` / `R.failed()` 统一格式。
|
||||
Reference in New Issue
Block a user