feat(dashboard): 最近动态改服务端分页
工作台「最近动态」原为聚合端点内嵌、固定截断前 20 条,操作日志变长后 既撑大响应又只能看到头部。改为独立分页端点: - GET /api/v1/dashboard/activities,支持 pageNum/pageSize/module 筛选 - 模块筛选项与列表同源返回(全量模块名,不随翻页变化),前端不必再取一次全量 - 聚合端点去掉内嵌 activities,避免同一份数据两处查询 前端改用 usePagedList + 统一 AppPagination(每页 10/20/50),模块筛选由 本地过滤改为服务端筛选。集成测试 13 例(含翻页不重不漏 / 模块筛选 / 越权 403)。 Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
1 parent
32b7940067
commit
61fe5cca98
7 files changed
+835
-329
No files matched your search
@@ -1,4 +1,4 @@
|
||||
"""工作台服务(M4 ⑧):四区块实时聚合编排。
|
||||
"""工作台服务(M4 ⑧):区块实时聚合编排 + 最近动态分页。
|
||||
|
||||
设计决策(2026-10-19):
|
||||
- **只读**:不落库、不写审计(读操作不入操作日志);总览只做 SQL 聚合,
|
||||
@@ -9,6 +9,8 @@
|
||||
- **⑥ 同步模块未启用**:同步失败待办、同步连续失败预警以
|
||||
``sync_available=false`` 显式降级,不返回伪造的 0 条
|
||||
- 预警阈值走参数体系(``warning.*``),一次请求只解析一次快照
|
||||
- **最近动态独立分页**(2026-10-23):操作日志可能很长,聚合响应里
|
||||
只能塞前 20 条;拆成独立端点后翻页只重取这张列表
|
||||
"""
|
||||
|
||||
from datetime import date, datetime, timedelta
|
||||
@@ -20,22 +22,23 @@ from app.core.exceptions import BadRequestError
|
||||
from app.core.month import validate_month
|
||||
from app.repositories import dashboard_repository, operation_log_repository, user_repository
|
||||
from app.repositories.query_utils import LogFilters
|
||||
from app.schemas.dashboard import ActivityItem, ActivityPageOut, ActivityQuery
|
||||
from app.services import approval_service
|
||||
|
||||
# 工作台只展示摘要,完整列表跳转对应管理页
|
||||
_TODO_LIMIT = 5
|
||||
_WARNING_LIMIT = 20
|
||||
_ACTIVITY_LIMIT = 20
|
||||
_TREND_MONTHS = 6
|
||||
|
||||
_ORDER_TYPE_LABELS = {1: "二次分配方案", 2: "月度结算", 3: "调整单"}
|
||||
|
||||
|
||||
def get_dashboard(session: Session, month: str | None = None, *, current_user) -> dict:
|
||||
"""四区块一次性出数(前端一次请求渲染整页)。
|
||||
"""三区块一次性出数(前端一次请求渲染整页)。
|
||||
|
||||
待办按当前用户角色只展示其可操作节点(admin 可查看全部在途单);
|
||||
风险预警仍是全局经营视角,不按人裁剪。
|
||||
最近动态不在此返回 —— 它是分页列表,走 ``list_activities``。
|
||||
"""
|
||||
resolved = _normalize_month(month)
|
||||
warning_params = _warning_params(session)
|
||||
@@ -47,7 +50,6 @@ def get_dashboard(session: Session, month: str | None = None, *, current_user) -
|
||||
"overview": _overview(session, resolved),
|
||||
"todos": _todos(session, pending_statuses),
|
||||
"warnings": _warnings(session, warning_params),
|
||||
"activities": _activities(session),
|
||||
}
|
||||
|
||||
|
||||
@@ -112,8 +114,8 @@ def _overview(session: Session, month: str) -> dict:
|
||||
for item in months
|
||||
],
|
||||
"note": (
|
||||
"绩效按台账归属月(单笔生效行,二次分摊拆行求和不失真);回款按到账月"
|
||||
"(含未核算回款);不含经理 12.5%+5% 聚合分成与调整单"
|
||||
"绩效按台账归属月统计(二次分配按参与人拆分后求和,不重复不计漏);"
|
||||
"回款按到账月统计(含尚未核算的回款);不含经理团队分成与调整单"
|
||||
),
|
||||
}
|
||||
|
||||
@@ -247,28 +249,38 @@ def _warnings(session: Session, params: dict) -> dict:
|
||||
}
|
||||
|
||||
|
||||
def _activities(session: Session) -> list[dict]:
|
||||
"""最近动态(FR-036):以操作日志为唯一来源(写操作即留痕)。"""
|
||||
logs = operation_log_repository.list_logs(
|
||||
session,
|
||||
operation_log_repository.OperationLogListQuery(
|
||||
filters=LogFilters(),
|
||||
offset=0,
|
||||
limit=_ACTIVITY_LIMIT,
|
||||
),
|
||||
def list_activities(session: Session, query: ActivityQuery) -> ActivityPageOut:
|
||||
"""最近动态分页(FR-036):以操作日志为唯一来源(写操作即留痕)。
|
||||
|
||||
模块筛选项与列表同源返回(全量模块名,不随当前页变化),
|
||||
前端模块下拉不必另取一次全量。
|
||||
"""
|
||||
repo_query = operation_log_repository.OperationLogListQuery(
|
||||
filters=LogFilters(),
|
||||
offset=query.offset,
|
||||
limit=query.page_size,
|
||||
module=query.module,
|
||||
)
|
||||
logs = operation_log_repository.list_logs(session, repo_query)
|
||||
total = operation_log_repository.count_logs(session, repo_query)
|
||||
return ActivityPageOut(
|
||||
records=[
|
||||
ActivityItem(
|
||||
id=log.id,
|
||||
module=log.module,
|
||||
action=log.action,
|
||||
summary=log.summary,
|
||||
username=log.username,
|
||||
success=log.success,
|
||||
create_time=log.create_time,
|
||||
)
|
||||
for log in logs
|
||||
],
|
||||
total=total,
|
||||
page_num=query.page_num,
|
||||
page_size=query.page_size,
|
||||
modules=operation_log_repository.distinct_modules(session),
|
||||
)
|
||||
return [
|
||||
{
|
||||
"id": log.id,
|
||||
"module": log.module,
|
||||
"action": log.action,
|
||||
"summary": log.summary,
|
||||
"username": log.username,
|
||||
"success": log.success,
|
||||
"create_time": log.create_time,
|
||||
}
|
||||
for log in logs
|
||||
]
|
||||
|
||||
|
||||
def _dec(value) -> Decimal | None:
|
||||
|
||||
Reference in new issue
Block a user