DevOps平台 — 第十六篇:动态的设计与实现

工作项解决「做什么」,规划解决「什么时候做」,里程碑和迭代解决「做到什么程度算一个阶段」。但团队成员还需要回答一个问题:「最近发生了什么?」------谁创建了工作项、谁开始了迭代、谁关闭了里程碑、谁编辑了文档。这些操作留痕需要被实时记录、按时间轴聚合、按维度筛选,让团队成员快速了解项目动态。本篇记录动态模块的数据模型、注解+切面写入机制、层级归集查询、视图 Tab、前端公共组件,以及多入口接入与概览预览改造。

一、动态要解决什么问题

1.1 痛点:两处「假动态」

在动态模块上线之前,平台有两处「假动态」:

位置 问题
迭代概览「动态」 用迭代+工作项+当前登录人在前端现拼,含捏造条目,无存储、无历史
项目概览「动态」 硬编码 mock 数据(张明/李雷...),纯占位

这两处都无法提供真实、持久、可追溯的活动流。用户看到的「动态」既不准确也不完整。

1.2 目标

用真实活动流替换假数据,实现:

  • 持久化存储:所有关键操作落库,可追溯
  • 层级归集:项目动态上卷子域(迭代/里程碑/知识库事件),企业动态上卷全项目
  • 个人视图:支持「全部 / 我创建的 / 我负责的 / 我参与的」四个视图 Tab
  • 分组与筛选:按天/按人/按业务域分组,支持人员、项目、迭代/里程碑筛选
  • 瀑布分页:无限滚动加载,而非传统分页
  • 公共组件:封装统一组件,多入口复用

二、数据模型

2.1 与审计日志解耦

平台已有审计日志模块,但动态选择独立建表,原因如下:

维度 审计日志 动态
目的 安全审计、合规追溯 团队协作、信息同步
粒度 每次操作逐字段变更记录 已渲染摘要,面向人类阅读
查询 按操作人/业务编号 按作用域/时间轴/关系人
展示 表格 + 字段变更对比 时间轴 + 摘要 + 头像
保留 30 天 永久(逻辑删除)

两者解耦后,动态可以面向用户体验做摘要渲染、关系人冗余、层级归集,不影响审计日志的合规性设计。

2.2 实体结构

动态实体继承基础业务实体,核心字段如下:

字段 类型 说明
所属企业 String 企业编码(归集根)
所属项目 Long 项目 ID(归集层;企业级无项目事件可空)
作用域类型 String 企业/项目/迭代/里程碑/知识库/工作项
作用域 ID Long 精确容器 ID
冗余迭代 ID Long 项目下按迭代筛选
冗余里程碑 ID Long 项目下按里程碑筛选
操作者 String 操作者用户名(展示 + 按人分组)
操作者展示名 String 冗余存储,免 join
目标创建人 String 目标实体的创建人(「我创建的」视图)
目标负责人 String 目标实体的负责人(「我负责的」视图)
协办人 String 目标实体协办人用户名逗号串(「我参与的」视图)
动作类型 String 创建/更新/删除/开始/完成/关闭/移入/移出等
目标类型 String 工作项/迭代/里程碑/知识库节点/项目/成员
目标 ID Long 目标实体 ID
摘要 String 已渲染摘要(如「创建了迭代「迭代 3 · 实时看板升级」」)
扩展 JSON String 字段变更/纳入移出信息/评论摘要等

设计要点:摘要在后端渲染后落库,而非前端拼接------确保历史记录不因前端版本变更而失真。操作者展示名冗余存储,避免每次查询都 join 用户表。关系人字段(创建人/负责人/协办人)描述的是「当前用户与目标实体的关系」,与操作者解耦。

2.3 作用域与归集

动态通过「作用域类型 + 作用域 ID」实现三级归集:

ini 复制代码
┌──────────────────────────────────────────────────────────────┐
│                      归集层级                                 │
├──────────────────────────────────────────────────────────────┤
│                                                              │
│  企业动态(作用域 = 企业)                                     │
│  ├── 归集:企业下全部项目的全部事件                            │
│  ├── 查询条件:企业编码 = 当前企业                             │
│  └── 筛选:项目下拉 + 人员下拉                                 │
│                                                              │
│  项目动态(作用域 = 项目)                                     │
│  ├── 归集:项目下全部子域事件(迭代/里程碑/知识库/工作项)       │
│  ├── 查询条件:项目 ID = 当前项目                              │
│  └── 筛选:迭代/里程碑下拉 + 人员下拉                          │
│                                                              │
│  容器动态(作用域 = 迭代/里程碑)                               │
│  ├── 归集:精确容器事件 + 冗余列上的子对象事件                  │
│  │   例:迭代动态 = 迭代自身事件 + 工作项在该迭代上的纳入/移出    │
│  ├── 查询条件:作用域匹配 OR 冗余列匹配                        │
│  └── 筛选:人员下拉                                           │
│                                                              │
└──────────────────────────────────────────────────────────────┘

冗余列的作用:一条工作项「纳入迭代」的动态,其作用域是「迭代」,但同时冗余了项目 ID 和迭代 ID。这样项目动态页可以按项目 ID 归集到这条动态,迭代动态页也可以按冗余的迭代 ID 归集到这条动态------无需 join。

三、写入机制

3.1 注解 + 切面

动态的写入采用自研注解 + AOP 切面模式,与平台已有的审计日志注解套路一致:

  • 注解:声明动态的元数据(作用域、动作、目标、摘要等),支持表达式从方法入参、返回值、上下文变量中动态取值
  • 切面:拦截注解方法,方法成功返回且事务提交后,解析表达式 → 组装记录 → 异步落库

注解属性支持三类值:

  1. 表达式 :以 # 开头,从方法入参、返回值、上下文变量中取值
  2. 静态方法调用:调用登录工具等获取当前用户等运行时信息
  3. 字面量:不含上述标记的字符串,直接使用

3.2 事务提交后落库

切面在方法成功返回且事务提交后才执行落库,原因:

  • 事务回滚时不记录动态(业务操作失败了,不应留下「成功」的动态)
  • 避免动态落库与业务操作在同一事务中,动态写失败导致业务回滚

落库失败时静默吞掉异常------动态是旁路记录,不应影响主业务流程。

3.3 栈式上下文

动态埋点支持嵌套场景 ------一个业务操作可能触发多个注解方法。为防止内层方法清除外层的上下文变量,采用栈式 Frame 设计:

ini 复制代码
┌──────────────────────────────────────────────────┐
│  线程局部栈(ThreadLocal<Deque<Map>>)             │
│                                                  │
│  ┌──────────────────┐  ← 栈顶(内层 Frame)       │
│  │ key: _skip=true  │                            │
│  │ key: itemTitle=X │                            │
│  └──────────────────┘                            │
│  ┌──────────────────┐  ← 外层 Frame              │
│  │ key: projectName=Y│                            │
│  └──────────────────┘                            │
│                                                  │
│  快照:自底向上合并,上层覆盖下层                   │
│  → { projectName: Y, itemTitle: X, _skip: true }│
└──────────────────────────────────────────────────┘
  • 切面进入时 push 新 Frame,退出时 pop
  • 业务代码通过 put 写入栈顶 Frame
  • 表达式解析时 snapshot 合并所有 Frame,上层覆盖下层
  • 内层可通过 _skip = true 跳过自身记录,不影响外层

3.4 Support Bean 模式

动态注解通过 AOP 代理生效,这意味着同类内部方法调用不会触发切面。为此,每个业务域抽取独立的 Support Bean:

Support Bean 职责
迭代动态支持 创建/更新/删除/开始/完成迭代
里程碑动态支持 创建/更新/删除/置顶/开始/关闭/重开里程碑
工作项动态支持 创建/编辑/删除(回收站)/恢复/彻底删除/状态流转工作项
工作项移动支持 纳入/移出迭代·里程碑 + 容器关闭批量回池
工作项协办人支持 查询协办人逗号串写入上下文(供 SpEL #collab)
知识库动态支持 创建文件夹/文档/上传/编辑/重命名/移动/删除/恢复/彻底删除/分享
项目动态支持 创建项目/更新设置/状态变更/成员加入/退出/身份变更
测试动态支持 用例/计划/评审/报告全生命周期埋点

Service 完成业务操作后,调用对应 Support Bean 的方法记录动态。Support Bean 内部通过上下文工具写入临时变量(如项目名、工作项标题、类型标签),注解的表达式从入参和上下文中取值组装摘要。

python 复制代码
┌──────────────────────────────────────────────────┐
│  Service 业务方法                                  │
│                                                    │
│  1. 业务操作(保存迭代)                            │
│                                                    │
│  2. 调用 Support Bean 记录动态                      │
│     iterationSupport.recordCreate(projectId, iter)│
│                                                    │
│     └─ 动态注解方法                                 │
│        ├── 表达式解析入参:迭代 ID、序号、名称        │
│        ├── 表达式解析上下文:临时变量                │
│        ├── 表达式调用静态方法:获取当前登录用户        │
│        └── 组装摘要:"创建了迭代「迭代 3 · 实时看板升级」"│
│                                                    │
│  3. 切面拦截 → 事务提交后 → 落库                    │
└──────────────────────────────────────────────────┘

四、埋点接入

4.1 事件目录

v1 接入的动态事件按业务域分类:

迭代:

动作 摘要示例
创建 创建了迭代「迭代 3 · 实时看板升级」
更新 更新了迭代「迭代 3 · 实时看板升级」
删除 删除了迭代「迭代 3 · 实时看板升级」
开始 开始了迭代「迭代 3 · 实时看板升级」
完成 完成了迭代「迭代 3 · 实时看板升级」

里程碑:

动作 摘要示例
创建 创建了里程碑「V1.0 发布」
更新 更新了里程碑「V1.0 发布」
删除 删除了里程碑「V1.0 发布」
置顶/取消置顶 置顶了/取消了置顶里程碑「V1.0 发布」
开始 开始了里程碑「V1.0 发布」
关闭 关闭了里程碑「V1.0 发布」
重新开启 重新开启了里程碑「V1.0 发布」

工作项:

动作 摘要示例
创建 创建了需求「用户登录优化」
编辑 编辑了任务「接口联调」
状态流转 将缺陷状态改为进行中「登录页白屏」
删除(回收站) 删除了任务「废弃需求」
恢复 恢复了任务「废弃需求」
彻底删除 彻底删除了任务「废弃需求」
纳入迭代 纳入了工作项「用户登录优化」(含容器链接)
移出迭代 移出了工作项「用户登录优化」(含容器链接)
纳入里程碑 纳入了工作项「用户登录优化」(含容器链接)
移出里程碑 移出了工作项「用户登录优化」(含容器链接)
批量回池 迭代/里程碑关闭时批量移出 N 个工作项(聚合一条)

知识库:

动作 摘要示例
创建文件夹 创建了文件夹「需求文档」
创建文档 创建了文档「接口规格说明」
上传附件 上传了附件「架构图.png」
编辑文档 更新了文档「接口规格说明」
重命名 重命名了「API 设计文档」
移动 移动了「API 设计文档」
删除(回收站) 删除了「旧版说明」
恢复 恢复了「旧版说明」
彻底删除 彻底删除了「旧版说明」
分享 分享了「架构图.png」

项目:

动作 摘要示例
创建项目 创建了项目「DevOps 平台」
更新设置 更新了项目「DevOps 平台」
状态变更 将项目状态改为进行中「DevOps 平台」
成员加入 将「张三」加入了项目
成员退出 将「李四」移出了项目
身份变更 将「王五」身份改为项目管理员

4.2 扩展 JSON

部分动态携带扩展信息,以 JSON 字符串存储:

扩展类型 场景 内容
字段变更 工作项更新 字段名、旧值、新值
纳入/移出 工作项移入/移出迭代·里程碑 方向(IN/OUT)、容器类型、容器 ID、容器展示名、批量回池数量
评论摘要 评论相关操作 评论内容摘要

前端根据扩展 JSON 渲染字段变更标签、容器跳转链接等富信息。

五、查询设计

5.1 两种查询模式

模式 用途 特点
分页查询 动态全量页 支持瀑布分页,每页 20 条
最新 N 条 概览预览 固定取最近 6 条,无分页

两种模式共享同一套查询条件(归集 + 筛选 + 视图),通过 SQL 片段复用,避免条件漂移。

5.2 查询条件

ini 复制代码
┌──────────────────────────────────────────────────────────┐
│  查询条件层叠                                              │
│                                                          │
│  1. 归集条件(必选其一)                                   │
│     ├── 精确容器:作用域类型 + 作用域 ID                    │
│     │   迭代/里程碑特殊:OR 冗余列匹配                      │
│     ├── 项目归集:项目 ID = ?                              │
│     └── 企业归集:企业编码 = ?(租户插件自动追加)          │
│                                                          │
│  2. 筛选条件(可选)                                       │
│     ├── 迭代筛选:冗余迭代 ID = ? OR 作用域匹配             │
│     ├── 里程碑筛选:冗余里程碑 ID = ? OR 作用域匹配         │
│     ├── 人员筛选:操作者 = ?                               │
│     ├── 动作类型筛选:动作类型 = ?                         │
│     └── 目标类型筛选:目标类型 = ?                         │
│                                                          │
│  3. 视图 Tab(可选)                                       │
│     ├── 全部:无条件                                       │
│     ├── 我创建的:目标创建人 = 当前用户                     │
│     ├── 我负责的:目标负责人 = 当前用户                     │
│     └── 我参与的:目标负责人 = 当前用户                     │
│                    OR 当前用户 IN (协办人列表)              │
│                                                          │
│  4. 排序:创建时间倒序 + ID 倒序(稳定排序)                │
└──────────────────────────────────────────────────────────┘

设计要点:迭代/里程碑的动态查询做了特殊处理------不仅匹配作用域为「迭代/里程碑」的动态,还匹配冗余列上指向该迭代/里程碑的子对象动态(如工作项纳入/移出动态)。这样迭代详情页的动态 Tab 能展示完整的活动流。

5.3 视图 Tab 的关系人语义

四个视图 Tab 描述的是「当前用户与目标实体的关系」,而非与操作者的关系:

视图 语义 查询条件
全部动态 当前作用域内全部活动 无额外条件
我创建的 目标实体的创建人 = 我 目标创建人 = 当前用户
我负责的 目标实体的负责人 = 我 目标负责人 = 当前用户
我参与的 我是负责人或协办人 目标负责人 = 当前用户 OR 当前用户在协办人列表中

操作者(actor)仅用于展示和按人分组,不参与视图过滤------即使操作者是别人,只要目标实体与我有关系,就会出现在我的视图中。

5.4 项目名补齐

企业动态 Feed 需要展示每条动态所属的项目名。为避免逐条查询,采用批量补齐策略:

  1. 收集结果集中所有不重复的项目 ID
  2. 一次性查询这些项目的名称
  3. 在内存中按 ID 映射回每条动态

六、前端公共组件

6.1 组件设计

动态模块封装了统一的公共组件,支持两种模式:

模式 触发场景 特点
全量模式 动态页/动态 Tab 显示视图 Tab + 筛选 + 瀑布分页
预览模式 概览页/概览 Tab 仅展示最近 N 条 + 「全部动态」按钮,无 Tab/筛选/分页

组件通过属性控制行为:

属性 说明
作用域类型 企业/项目/迭代/里程碑/知识库
作用域 ID 对应的实体 ID
项目 ID 迭代/里程碑场景下兜底用
是否显示视图 Tab 概览预览时可关闭
默认视图 初始视图 Tab
筛选项显隐 控制项目/人员/迭代里程碑筛选下拉的显示
是否预览 预览模式开关
预览条数 预览模式下的条数(默认 6)

6.2 数据流

scss 复制代码
┌──────────────────────────────────────────────────────┐
│  ActivityFeed 组件                                     │
│                                                      │
│  Props → useActivityFeed 组合式函数                   │
│    ├── 作用域类型/ID → 构建基础查询                      │
│    ├── 视图 Tab 变化 → 重置列表                         │
│    ├── 筛选变化 → 重置列表                              │
│    └── 加载更多 → 页码+1,追加列表                      │
│                                                      │
│  分组计算(computed)                                   │
│    └── groupActivities(已加载列表, 'day')             │
│        → 按天分组 → 天内按人分组                        │
│                                                      │
│  渲染                                                  │
│    ├── 预览头(预览模式)                               │
│    ├── 视图 Tab(全量模式)                             │
│    ├── 筛选栏(全量模式)                               │
│    ├── 按天分组列表                                     │
│    │   ├── 天标题(今天/昨天/日期 + 条数标签)           │
│    │   └── 人员块                                      │
│    │       ├── 头像 + 操作人名                          │
│    │       └── 操作列表(折叠/展开)                     │
│    │           ├── 图标 + 摘要 + 时间                   │
│    │           ├── 字段变更标签                          │
│    │           ├── 纳入/移出容器链接                    │
│    │           └── 评论摘要                            │
│    └── 加载更多 / 没有更多了                            │
└──────────────────────────────────────────────────────┘

6.3 筛选项

不同入口的筛选项不同:

入口 项目筛选 迭代/里程碑筛选 人员筛选
企业动态 ✅ --- ✅
项目动态 --- ✅ ✅
迭代动态 --- --- ✅
里程碑动态 --- --- ✅

人员筛选在视图 Tab 为「全部动态」时显示,切换到个人视图(我创建的/我负责的/我参与的)时自动隐藏------个人视图已经隐含了人员过滤。

七、分组与折叠

7.1 按天 → 天内按人

动态列表默认按天分组,天标题显示「今天/昨天/日期」+ 条数标签。同一天内再按操作人分组,人员块按其最新一条动态的时间倒序排列。

ini 复制代码
┌──────────────────────────────────────────────────┐
│  今天                              [12]          │
│                                                  │
│  👤 张三                                          │
│  ┃ ● 创建了迭代「迭代 3 · 实时看板升级」  10:32   │
│  ┃ ● 开始了迭代「迭代 3 · 实时看板升级」  10:35   │
│  ┃ ● 纳入了工作项「用户登录优化」        10:38   │
│  ┃   └→ 迭代 3 · 实时看板升级                     │
│  ┃                                                │
│  👤 李四                                          │
│  ┃ ● 创建了需求「接口联调」              09:15    │
│  ┃ ● 更新了任务「前端适配」              09:20    │
│  ┃   字段: 负责人 张三 → 李四                    │
│                                                  │
│  昨天                              [5]           │
│  👤 王五                                          │
│  ┃ ● 关闭了里程碑「V1.0 发布」           18:00    │
│  ┃ ...                                           │
└──────────────────────────────────────────────────┘

7.2 人员块折叠

当某个人在一天内的操作超过 5 条时,默认折叠为前 3 + 后 2,中间显示折叠按钮。点击展开后显示全部操作,按钮变为「收起」。

ini 复制代码
折叠态:
┃ ● 操作1  10:30
┃ ● 操作2  10:31
┃ ● 操作3  10:32
┃ [已折叠 8 条,点击展开]
┃ ● 操作11 10:45
┃ ● 操作12 10:46

展开态:
┃ ● 操作1  10:30
┃ ● 操作2  10:31
┃ ● 操作3  10:32
┃ [收起]
┃ ● 操作4  10:33
┃ ● 操作5  10:34
┃ ...(全部展示)

7.3 瀑布分页

分页采用瀑布模式(无限滚动),而非传统分页:

  • 每页 20 条,追加到列表末尾
  • 滚动到底部自动加载下一页(也可点击「加载更多」按钮)
  • 显示「已展示 N / 总数」计数
  • 加载完毕显示「没有更多了」

筛选/视图/作用域变化时重置列表,从第一页开始重新加载。

八、多入口接入

8.1 接入清单

入口 作用域 模式 筛选
企业动态侧栏 企业 全量 项目 + 人员
项目动态页 项目 全量 迭代/里程碑 + 人员
迭代详情动态 Tab 迭代 全量 人员
里程碑详情动态 Tab 里程碑 全量 人员
项目概览预览 项目 预览 ---
迭代概览预览 迭代 预览 ---
里程碑概览预览 里程碑 预览 ---

8.2 概览预览改造

动态模块上线后,原有的两处假动态被替换:

改造点 改造前 改造后
项目概览动态 硬编码 mock 预览模式,取最近 6 条真实动态
迭代概览动态 前端拼装 预览模式,取最近 6 条真实动态
里程碑概览动态 无 预览模式,取最近 6 条真实动态

预览模式下展示扁平时间轴 + 「全部动态」按钮,点击跳转到对应的动态全量页。

8.3 企业动态侧栏

企业工作台的主侧栏在「统计」与「成员」之间新增「动态」入口,点击进入企业动态页,展示全企业的操作留痕,跨项目按时间轴聚合。

8.4 项目动态页

项目侧栏的「动态」导航项之前为占位状态(显示「模块规划中」),动态模块上线后接入真实页面,展示项目下全部子域事件,支持迭代/里程碑和人员筛选。

九、设计要点总结

javascript 复制代码
┌──────────────────────────────────────────────────────────────┐
│                      动态模块设计要点                          │
├──────────────────────────────────────────────────────────────┤
│                                                              │
│  1. 与审计日志解耦:独立活动表,面向用户体验                   │
│     摘要后端渲染落库,历史不因前端版本失真                     │
│                                                              │
│  2. 注解+切面写入:自定义注解 + 表达式 + 事务提交后落库      │
│     落库失败静默吞掉,不影响主业务                             │
│                                                              │
│  3. 栈式上下文:ThreadLocal<Deque<Map>> 嵌套 Frame          │
│     内层 put 不清除外层,_skip 不影响外层                     │
│                                                              │
│  4. Support Bean 模式:每域独立 Bean,保证代理生效             │
│     Service 调 Support,Support 带注解                        │
│                                                              │
│  5. 三级归集:企业→项目→迭代/里程碑/知识库                    │
│     冗余列双路径:精确作用域 + 冗余迭代/里程碑 ID              │
│                                                              │
│  6. 视图 Tab:全部/我创建的/我负责的/我参与的                  │
│     关系人字段与操作者解耦,描述用户与目标实体的关系            │
│                                                              │
│  7. 两种查询:分页(瀑布)+ 最新 N 条(预览)                 │
│     共用 SQL 片段,条件不漂移                                 │
│                                                              │
│  8. 公共组件:ActivityFeed 统一组件                           │
│     预览/全量双模式,视图 Tab + 筛选 + 瀑布分页               │
│                                                              │
│  9. 分组折叠:按天→天内按人,人员块折叠/展开                  │
│     >5 条折叠为前3+后2,点击展开                              │
│                                                              │
│  10. 多入口接入:企业侧栏/项目页/迭代Tab/里程碑Tab/概览预览    │
│      替换两处假动态,概览预览取真实数据                        │
│                                                              │
│  11. 事件目录:迭代/里程碑/工作项/知识库/项目/测试域            │
│      v1 接入六大域,版本预留枚举暂不埋点                        │
│                                                              │
│  12. 扩展 JSON:字段变更/纳入移出/评论摘要                    │
│      富信息渲染,容器跳转链接                                 │
│                                                              │
└──────────────────────────────────────────────────────────────┘

附:测试域接入(用例 / 评审 / 计划 / 报告)

测试域四类实体沿用同一套注解 + 切面机制,新增 ActivityTestSupport 独立 Bean,作用域按实体细分,避免 ID 撞车:

实体 scopeType / targetType 冗余字段 主要动作
用例 TEST_CASE projectId 创建 / 编辑 / 新版本 / 复制 / 归档 / 恢复 / 回滚
计划 TEST_PLAN projectId + iterationId + milestoneId 创建 / 更新 / 复制 / 添加用例 / 移除用例 / 指派 / 取消指派 / 开始 / 挂起 / 继续 / 结束 / 作废 / 执行 / 修改执行结果
评审 TEST_REVIEW projectId 创建 / 更新 / 添加用例版本 / 提交评审结论 / 开始 / 挂起 / 继续 / 结束 / 作废
报告 TEST_REPORT projectId 生成 / 更新

三个设计要点:

  1. 作用域细分 :scope_type 使用 TEST_* 而非单一 TEST,详情页可用 scope_type + scope_id 精确查询,且 idx_act_scope_time 直接复用。
  2. 目标可跨域 :计划内「移除用例 / 指派 / 执行」与评审「提交结论」的 scope 仍属于计划/评审,但 targetType + targetId 指向用例。用例详情按 targetType + targetId 聚合,即可同时看到本用例的编辑、评审结论与执行记录。
  3. 报告无详情入口 :报告详情是列表页抽屉,动态只落库,在项目 / 企业动态中查看;点击报告动态会带 reportId 深链到报告列表并自动打开抽屉。

新增查询参数 targetId(与 targetType 搭配)及索引 idx_act_target_time (target_type, target_id, create_time DESC);前端 ActivityFeed 增加 targetType / targetId 两个可选属性与「按业务域筛选」能力。

测试域动态当前未使用 extJson 扩展字段------摘要已自包含足够信息(如执行结果「通过/失败/受阻」、评审结论「通过/不通过」、指派人名等),均通过 SpEL 在后端渲染后落库 summary。后续若需携带字段级变更(如用例步骤对比),可复用与工作项相同的 extJson.change 结构。


附二:按天查询与逐日累积(v2)

动态流由「分页瀑布」调整为「按天查询 + 逐日向前加载」:

  • 新增 GET /companies/{companyCode}/activities/day?date=YYYY-MM-DD,返回该日 [00:00:00, 次日 00:00:00) 的全部事件(半开区间 ,避免 23:59:59.999 漏数据),不分页
  • 其余筛选参数(作用域 / 项目 / 人员 / 视图 / 目标 / 迭代 / 里程碑)完全复用
  • 前端默认加载今天;「加载前一天数据」按钮常驻,点击后按最旧已加载日期继续向前追加一天
  • 展示分三级:按天分组 → 天内按人分组 → 组内时间倒序;没有数据的日期不渲染分组
  • 每条记录的操作时间 HH:mm:ss 紧贴摘要文本展示(非右对齐),悬停显示完整 YYYY-MM-DD HH:mm:ss
  • 概览预览仍走 /latest(最新 N 条),行为不变

日期边界与时区:前端发送浏览器本地 YYYY-MM-DD,后端按服务器默认时区解释为当天 00:00 至次日 00:00;部署时需保证两端时区一致。

相关推荐
136096757231 小时前
微信校验文件不用文件
后端
福大大架构师每日一题1 小时前
2026-10-20:统计二叉树中支配节点的数量。用go语言,给定一棵完全二叉树的根节点 root,树中每个节点都有一个值。 对于一个节点 x,考察由 x 本身
后端
SensorFlow1 小时前
测试埋点别混进正式报表:环境隔离、身份标记与查询口径三层验收
后端
从零到一未来可期1 小时前
第6集:RAG检索不准?3个参数调优路线图
后端
柠檬味拥抱1 小时前
空中目标检测数据集 | 8900张YOLO低空安防数据集
后端
2601_961963381 小时前
电子合同检索与全文搜索怎么测、怎么选:六个指标 + 五家平台对比 + 八个自测问题
数据库·后端·python·django·智能合约
Code_Artist2 小时前
论反射编程的魅力——程序如何在运行时认识自己?
后端·源码·编程语言
UaoN2 小时前
作为全栈开发者,为什么看到 Shopify 回归原生,我依然选择 React Native
前端·后端
打工仔折腾 AI2 小时前
从零开始大模型微调:基于 PyTorch 与 ChatGLM 的 LoRA 实践指南
人工智能·pytorch·后端·python·深度学习·性能优化·ai agent 实战