前端给AI消息做日期分组与时间线

先说结论:把一长条 AI 对话消息变成清爽的时间线,核心就两步------按会话(session)分组 、再按日期(今天/昨天/更早)打标签 。数据层用 reduce 归并,渲染层做粘性日期头,不用引第三方库。下面是我前两周真踩过的活儿,代码能直接抄。

起因

我在给一个自己搭的 AI 小助手做 web 端聊天界面。后端把消息一股脑按时间正序吐回来,前端就一条接一条往下堆。测了两天,消息攒到三百多条的时候,整个面板糊成一坨------你根本分不清哪句是今早问的,哪句是上周那次会话留下的。产品同事(其实就是我自己兼)看了一眼说:太脏了。

行吧。

第一步:数据先分好组,别在 JSX 里硬塞

我见过有人直接在模板里 if (上一条日期 !== 这条日期) 插分隔线,能跑,但乱。先在数据层把扁平数组捏成分组结构。

scss 复制代码
// 假设每条 msg: { id, sessionId, content, role, createdAt }
function groupBySession(messages) {
  const map = new Map();
  for (const m of messages) {
    if (!map.has(m.sessionId)) map.set(m.sessionId, []);
    map.get(m.sessionId).push(m);
  }
  // Map 保插入顺序,会话天然按首次出现排好
  return [...map.entries()].map(([sessionId, list]) => ({
    sessionId,
    list,
    startAt: list[0].createdAt,
  }));
}

会话内再不用动,组与组之间按 startAt 倒序就是最近的会话在最上面。

第二步:日期标签,别去算"几天前"

这步是我栽过的坑。一开始我吭哧吭哧写 Math.floor((now - t) / 86400000) 去算差几天,结果跨午夜就错------晚上23:50和凌晨0:10明明隔了20分钟,算出来"0天",可它俩分属两天,得分到两组。

正解是比日历日,不是比时间差:

ini 复制代码
function dayLabel(ts) {
  const d = new Date(ts);
  const today = new Date();
  const ymd = x => x.getFullYear() * 10000 + (x.getMonth() + 1) * 100 + x.getDate();
  const diff = ymd(today) - ymd(d);
  if (diff === 0) return '今天';
  if (diff === 1) return '昨天';
  if (diff < 7) return d.toLocaleDateString('zh-CN', { weekday: 'long' }); // 周三
  return `${d.getMonth() + 1}月${d.getDate()}日`;
}

把日期戳压成 年*10000+月*100+日 这个整数再相减,天数差就稳了,不受具体几点几分干扰。

第三步:粘性日期头,滚动时吸顶

时间线的"清爽感"一大半来自滚动时那个日期标签会黏在顶上。纯 CSS 就够:

css 复制代码
.day-label {
  position: sticky;
  top: 0;
  z-index: 2;
  /* 别忘了背景色,不然下面的消息会透上来糊一起 */
  background: #f7f8fa;
}

background 那行我忘了写,调了十分钟以为是 z-index 的事,结果是文字和下面气泡叠透了。记一下。

一点真实的取舍

会话分组我没做"自动归并相近时间的消息"那种智能合并------比如隔了2小时的两次提问算不算一个会话。试过,阈值定多少都有人觉得不对,干脆老老实实信后端给的 sessionId,前端只管展示。少做一点反而稳。

另外说句实话,难看的不是布局,是内容本身。我那个 AI 小助手第一版回答又干又短,时间线做得再漂亮,点开每条都是两行废话也白搭。后来我给它配了点私有资料喂进去(RAG 那套),回答才有了血肉,时间线翻起来才像回事。

对了,搭这个小助手我基本没写后端------拖一拖配一配,挂个现成模型、传几份文档当知识库,发布成一个 API,前端直接调。我一个偏前端的人,零代码就把"智能体"那部分糊出来了,省下的精力全砸在这个时间线交互上了。

收尾

分组的活儿听着小,做到"一眼就清爽"挺费心思的------比 ymd 那个整数 trick 还琐碎的细节有七八处。但用户滑动时那个日期标签稳稳吸在顶上的瞬间,值。

你们做聊天记录的日期分组,是信后端 sessionId 还是前端自己按时间切?评论区聊聊,我那套阈值方案就是被同行劝退的。

(背后那个智能体我挂的是讯飞的 MaaS,现成大模型直接调 API,没自己部署算力,省心。)

相关推荐
i晟1 小时前
Claude Code Harness 深度拆解:从你敲回车到模型回复,中间发生了什么
人工智能
用户252736278142 小时前
【踩坑复盘】我在本地跑 RAG 知识库时踩了 5 个大坑,吐血整理避坑指南
人工智能
大模型真好玩2 小时前
LangChain DeepAgents 速通指南(九)—— 生产级智能体框架 DeepAgents Code 源码导读
人工智能·langchain·agent
用户018349301695 小时前
用Zustand管理AI多会话状态
人工智能
武子康7 小时前
调查研究-198 Agent 到底该记住什么?读懂《What Must Generalist Agents Remember?》
人工智能·openai·agent
aqi008 小时前
15天学会AI应用开发(九)利用Chroma持久化向量数据
人工智能·python·大模型·ai编程·ai应用
武子康9 小时前
调查研究-197 FAISS vs Elasticsearch 全面对比:从向量检索、全文搜索到 RAG 选型指南
人工智能·elasticsearch·agent
青禾网络9 小时前
Web 前端如何接入 AI 音效生成:从零到可用的完整方案
人工智能·设计模式