Browse Source

fix(client): 历史会话时间智能分档显示并修复操作栏按钮 tooltip

历史会话列表时间由原始 ISO 字符串改为智能分档:今天/昨天显示 HH:mm,同年显示 MM-DD HH:mm,跨年显示 YYYY-MM-DD HH:mm。

操作栏按钮(重新生成/复制/点赞/点踩)补齐 hover 文字说明:修复 tooltip 浮层 z-index 低于聊天窗(9999)被遮挡,及 .t-tooltip 深色背景样式在 light DOM 浮层缺失的问题(globalCSS 只对 shadow DOM 生效)。
master
wanghanlin 4 days ago
parent
commit
b56cea0c8c
  1. 10
      client/src/dom.ts
  2. 20
      client/src/styles.ts
  3. 21
      client/src/utils.ts

10
client/src/dom.ts

@ -8,7 +8,7 @@
* - * -
*/ */
import { ResolvedConfig, RagSource } from './types'; import { ResolvedConfig, RagSource } from './types';
import { debounce, formatTime } from './utils';
import { debounce, formatTime, formatHistoryTime } from './utils';
import { t } from './i18n'; import { t } from './i18n';
import { DialogPlugin } from 'tdesign-web-components/lib/dialog/index.js'; import { DialogPlugin } from 'tdesign-web-components/lib/dialog/index.js';
// omi 的 render/h 用于创建带 on* 函数回调的组件(见 createEventful 说明) // omi 的 render/h 用于创建带 on* 函数回调的组件(见 createEventful 说明)
@ -915,8 +915,11 @@ function createChatAction(wrapper: HTMLElement, text: string, msgId?: string, fe
const el = actionEl as unknown as { const el = actionEl as unknown as {
actionBar: string[]; actionBar: string[];
handleAction: (action: string, data: { event?: Event; active?: boolean }) => void; handleAction: (action: string, data: { event?: Event; active?: boolean }) => void;
tooltipProps: Record<string, unknown>;
}; };
el.actionBar = ['replay', 'copy', 'good', 'bad']; el.actionBar = ['replay', 'copy', 'good', 'bad'];
// 浮层 portal 到 body:zIndex 越过弹窗(9999)防遮挡,overlayClassName 加 SDK 私有类用于补样式
el.tooltipProps = { overlayClassName: 'csk-tooltip', zIndex: 10000 };
// copyText/comment 为 String 简单类型,须用 setAttribute(property 赋值在 omi 下静默失效) // copyText/comment 为 String 简单类型,须用 setAttribute(property 赋值在 omi 下静默失效)
actionEl.setAttribute('copyText', text); actionEl.setAttribute('copyText', text);
actionEl.setAttribute('comment', feedback === 'up' ? 'good' : feedback === 'down' ? 'bad' : ''); actionEl.setAttribute('comment', feedback === 'up' ? 'good' : feedback === 'down' ? 'bad' : '');
@ -1160,8 +1163,9 @@ export function renderHistoryList(
const metaParts: string[] = []; const metaParts: string[] = [];
if (item.roleName) metaParts.push(item.roleName); if (item.roleName) metaParts.push(item.roleName);
if (item.messageCount !== undefined) metaParts.push(`${item.messageCount} 条消息`); if (item.messageCount !== undefined) metaParts.push(`${item.messageCount} 条消息`);
if (item.lastMessageTime) metaParts.push(item.lastMessageTime);
else if (item.createdAt) metaParts.push(item.createdAt);
const timeStr = item.lastMessageTime || item.createdAt;
const timeText = formatHistoryTime(timeStr);
if (timeText) metaParts.push(timeText);
metaEl.textContent = metaParts.join(' · '); metaEl.textContent = metaParts.join(' · ');
info.appendChild(idEl); info.appendChild(idEl);

20
client/src/styles.ts

@ -624,6 +624,26 @@ function getStyles(config: ResolvedConfig): string {
.csk-launcher, .csk-teaser { box-sizing: border-box; } .csk-launcher, .csk-teaser { box-sizing: border-box; }
.csk-launcher *, .csk-teaser * { box-sizing: border-box; } .csk-launcher *, .csk-teaser * { box-sizing: border-box; }
/* ===== tooltip t-popup portal bodylight DOM =====
* .t-tooltip globalCSSconstructable stylesheet shadow DOM
* portal document.body light DOM csk-tooltip 宿
* tdesign-web-components v1.2.10 _chunks/dep-a3fbe4be.jscss_248z */
.csk-tooltip .t-popup__content {
display: inline-block;
border: 0;
z-index: 5600;
margin-bottom: 1px;
max-width: 480px;
word-break: break-word;
box-sizing: border-box;
border-radius: var(--td-radius-medium);
color: var(--td-text-color-anti);
background: var(--td-gray-color-13);
box-shadow: inset 0 0.5px 0 var(--td-gray-color-9), inset 0.5px 0 0 var(--td-gray-color-9), inset 0 -0.5px 0 var(--td-gray-color-9), inset -0.5px 0 0 var(--td-gray-color-9);
}
.csk-tooltip .t-popup__arrow { background: inherit; height: auto; }
.csk-tooltip .t-popup__arrow::before { background: inherit; }
/* ===== t-taglight DOM ===== /* ===== t-taglight DOM =====
* t-tag tdesign-web-components light DOM isLightDOM: true .t-tag * t-tag tdesign-web-components light DOM isLightDOM: true .t-tag
* globalCSS constructable stylesheet globalCSS shadow DOM * globalCSS constructable stylesheet globalCSS shadow DOM

21
client/src/utils.ts

@ -40,6 +40,27 @@ export function formatTime(timestamp: number): string {
return `${hh}:${mm}`; return `${hh}:${mm}`;
} }
/** 格式化历史会话时间:今天/昨天显示 HH:mm,同年显示 MM-DD HH:mm,跨年显示 YYYY-MM-DD HH:mm */
export function formatHistoryTime(timeStr: string | undefined): string {
if (!timeStr) return '';
const d = new Date(timeStr);
if (isNaN(d.getTime())) return timeStr; // 解析失败原样返回,避免破坏展示
const pad = (n: number) => String(n).padStart(2, '0');
const hh = pad(d.getHours());
const mm = pad(d.getMinutes());
const now = new Date();
const todayStart = new Date(now.getFullYear(), now.getMonth(), now.getDate()).getTime();
const yesterdayStart = todayStart - 86400000;
const ts = d.getTime();
// 今天或昨天:只显示时分
if (ts >= yesterdayStart) return `${hh}:${mm}`;
const md = `${pad(d.getMonth() + 1)}-${pad(d.getDate())}`;
// 今年内:月-日 时分
if (d.getFullYear() === now.getFullYear()) return `${md} ${hh}:${mm}`;
// 跨年:完整年月日 时分
return `${d.getFullYear()}-${md} ${hh}:${mm}`;
}
/** 获取当前时间戳(毫秒) */ /** 获取当前时间戳(毫秒) */
export function now(): number { export function now(): number {
return Date.now(); return Date.now();

Loading…
Cancel
Save